I have two tables in my sample database. These are called:
Active Products.
Inactive Products
In my asp form I have two list boxes and a dropdown list.
DropDown List: Category.
When I select any one category like milk products in my dropdown list, it will show these products under list in the category on my Left side.
Products to Active. - [ Left Side ]
Activated Products. - [ Right side ]
I used to buttons for move the list items for move left and right side. When I click an update button, it will take the list items what contains on right side list box and insert these items in first table called Active Products.
Now I select two list items on my right side and I move them to left side list box and click update button, that moved items are updated in second table. How do I do this?
Active table:
Categoryid | Produtid
-----------+-----------
1 1
1 5
1 6
Example if i select a first category, that corresponding products were display in right side, if i move Productid 5 and 6 on left side.
It will be deleted in this table updated on in-active table.
My expected output will be look like this, how to wrote function for getting this output. someone please guide me. Thanks in advance,
Active table:
Categoryid | Produtid
-----------+---------
1 1
Inactive table:
Categoryid | Produtid
-----------+----------
1 5
1 6
For inserting:
INSERT INTO InactiveTable
SELECT * FROM ActiveTable WHERE RowId = "<insert rowid>"
For deleting:
DELETE FROM ActiveTable
WHERE RowId = "<insert rowid>"
Obviously insert before you delete.
First of, I'd suggest you use an Active/Inactive flag (just add a bit to your table).
If that's really not what you want, you can write an SQL-trigger. Should look something like this:
CREATE TRIGGER dbo.SetActiveProductToInactive
ON dbo.ActiveProducts
FOR DELETE
AS
INSERT INTO dbo.InactiveProducts
SELECT * FROM deleted
GO
This inserts all deleted items into your ActiveProducst table before actually deleting them. If this is too much for what you are trying to accomplish, you should look at James' answer.
when you delete row it returns record. Try this.
Creating new table:
CREATE TABLE archived_table_timestamp AS WITH deleted_rows as
(DELETE FROM main_table RETURNING *)SELECT * FROM deleted_rows;
to insert in existing table:
WITH deleted_rows as (
DELETE FROM active_table WHERE 'condition' RETURNING *
)
INSERT INTO archived_table SELECT * FROM deleted_rows;
As #Nick.McDermaid mentioned in the comments it would be better to have Inactive flag on the product table. But if you still need to move these rows between to tables you can use OUTPUT clause to do that just in a single statement.
First we are creating these to tables
create table #Active (Categoryid int, Productid int);
create table #Inactive (Categoryid int, Productid int);
Second we are inserting these records
insert into #Active (Categoryid, Productid) values (1, 1), (1, 5), (1, 6);
Third we are deleting some rows from #Active table and inserting them to the #Passive table
delete t
output deleted.*
into #Inactive
from #Active AS t
where t.Productid in (5, 6);
If you need much more details about OUTPUT clause you can visit that link:
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql
Related
I have 3 tables:
Staging: that gets employee records inserted every month.
Master: table has contains all previously entered records from staging, unique records.
Changes: keeps track of all changes - has no primary key.
The tables have 10 columns. In the staging table, every month we have about 2,500,000 records. Using a cursor I am able to insert new records from staging into the master table.
When it comes to update, I am using an inner join to get the records from staging that already exist in the master table.
To find out if any of the employee info has changed, do I have to query something line this:
WHERE Staging.FirstName <> Master.FirstName
OR Staging.LastName <> Master.LastName
OR ...
And so on for 10 columns, or is there an easier way?
If the two tables really are identical, you could create a persisted computed column in each table that represents a checksum of the entire row (see http://technet.microsoft.com/en-us/library/ms189788.aspx), create an index on that, and then use that for your joins.
Using a Cursor for millions of rows does not sound like fun.
Maybe you should look at EXCEPT/MERGE
WITH NewAndChanged AS (
SELECT Stage.Id
,Stage.Col1
,Stage.Col2
FROM Stage
EXCEPT
SELECT Master.Id
,Master.Col1
,Master.Col2
FROM Master
)
MERGE Master
USING NewAndChanged
ON Master.Id = NewAndChanged.Id
WHEN MATCHED
THEN UPDATE SET
Col1 = NewAndChanged.Col1
,Col2 = NewAndChanged.Col2
WHEN NOT MATCHED
THEN INSERT (
Id
,Col1
,Col2
)
VALUES (
NewAndChanged.Id
,NewAndChanged.Col1
,NewAndChanged.Col2
)
Lets say I have a DataBase table that associates an Id with multiple items.
Say ID with favorite food.
So it looks like
Id FoodId
----------
1 1
1 54
1 543
2 42
2 4234
etc
I can select/ unselect favorite food values using my checked list box
When I update the db after I edit the items, do I go back and delete all previous entries in the table with Id 1 and then enter the whole new set or is there a better way of doing this?
The easiest way would be your approach. But it is also the slowest and generates redundant database operations. The correct way would be to have the old and the new list in memory creating delete, insert statements accordingly.
Compare the two lists and remove all identical values from both lists.
Create DELETEstatements for all remaining values in the 'old' list.
Create INSERTstatements for all remaining values in the 'new' list.
DELETE
FROM favfood
WHERE id=#Id and foodid not in(new_list_of_food_ids)
// serialized new_list_of_food_ids
INSERT INTO favfood(id,foodid)
(SELECT #Id, [int]
FROM OPENXML (#idoc, '/ArrayOfInt/int',1)
WITH ([int] int '.')
where [int] not in (select foodid from favfood where id=#Id))
I have table called customers contain custID,custName, another table called products contain proID,proName,price and third table Cust_PRo contain id,custID,proID.
i filled the products with data like this:
proID proName price
1 potato 100
2 cotton 600
3 rice 200
and in another form i have combobox i filled it with products names and textbox to write the customer name and gridview to appear data and there are two buttons one to add the values into grid and second to save it into database.
when i write the customer name and choose the products the data appear in the grid like this:
custName ProName
john potato
john cotton
john rice
as you see one customer can take many products the problem is to add the values into database i want when the user click the save button the data insert into the database like this:
first customers table:
custID custName
1 john
second Cust_PRo table:
id custID ProID
1 1 1
2 1 2
3 1 3
thank you
i'm not sure i got you 100% but i think you need some algorithm or something.. anyway
first, you need to generate a CustID for your new customer, to do that you need to get the maximum CustID from the table Customers and add it to 1 to avoid Primary key violation.
select max(CustID) from Customers
then, you'll be good to go. You have (CustID and ProdID from comboBox1.SelectedValue;)
I added the values to datatable and then used the SqlBulkCopy class to insert these values into database
In my application, i want to show the newly added RECORDS by an import operation in a gridview. Is there is any method in sql to retrive newly added rows.
I tried to do it in using code and tried to get the difference before and after the insertion and its working perfectly but makes the application very slow. So, i want to do it in database itself.
Im using Mysql, ASP.NET.
Eg:
table may have these records before the import operation
ID Name
1 A
2 B
3 C
and after import the table may be like this.
ID Name
1 A
2 B
3 C
4 D
5 E
6 F
I want result like
ID Name
4 D
5 E
6 F
You need to have AUTO_INCREMENT column defined on table or alternatively you can use TIMESTAMP field to retrieve newly added records, try this:
SELECT *
FROM table_name
ORDER BY id DESC
LIMIT 10;
For single row insert you can use LAST_INSERT_ID after you INSERT query:
SELECT LAST_INSERT_ID();
For multi-row insert you can follow these steps:
START TRANSACTION;
SELECT MAX(id) INTO #var_max_id FROM table_name;
INSERT INTO table_name VALUES(..),(..),...;
SELECT MAX(id) INTO #var_max_id_new FROM table_name;
COMMIT;
SELECT *
FROM table_name
WHERE id BETWEEN (#var_max_id + 1) AND #var_max_id_new;
i think this will be more simple:
SELECT MAX(id) INTO #Max_table_Id FROM table;
// Insert operation here//////
SELECT * FROM table WHERE id>#Max_table_Id;
In case you use auto incremental IDs for your records, you can use:
SELECT * FROM [table] ORDER BY [id column] DESC LIMIT [number of records]
Otherwise you should add a TIMESTAMP colum to your records for this purpose and select by this column.
Personally, if there is an option, I wouldn't use the record IDs for this, as it is not what they are for. Record IDs can change throughout the lifetime of an application and they don't necessarily represent the order in which the items were added. Especially in data import/export scenarios. I'd prefer to create special columns to store such information, e.g. "CreatedAt", "ModifiedAt".
This is something that has bothered me for a while, and I finally want to get an answer to it.
Say I have Employees and Departments. There's a many-to-many relationship between the two, with an association table named EmployeeDepartments.
Employees
-------------------
EmployeeID (PK)
Departments
-------------------
DepartmentID (PK)
EmployeeDepartments
-------------------
EmployeeID (FK)
DepartmentID (FK)
I have a page where a user can edit an employee. There is a list of checkboxes that shows all the departments, and the departments that the employee belongs to will be checked. The user can then check/uncheck which departments the employee belongs to.
When I edit an employee and go to save the data, how should I handle those departments?
The way I've been doing it is to delete every record in the EmployeeDepartments table for that employee. And then for each department that the user selected, I add it to EmployeeDepartments.
It works, but there has to be a more efficient way to do this, it just seems wrong. If an employee is in 5 departments, and I go to add that employee to another department, I will have to delete 5 records from EmployeeDepartments, and then add 6 records.
Just process the change delta. That is, look at the currently "selected" items, then the items to select, and then either add or delete appropriate. This can be computed using the set operations (which are trivial in LINQ).
Delete items in old - new (set difference, or Except)
Add items in new - old (set difference, or Except)
(Items in new ^ old should be unaffected)
Much of this work can be handed off to the database, if desired. (Delete except where... and insert if not exists... for instance. Also see the Standard SQL MERGE statement and non-Standard equivalents and extensions).
Make sure to correctly use database transactions to ensure consistency.
Happy coding.
If your SQL product supports it, you can use Standard SQL's MERGE. If your SQL product is SQL Server then you are in luck: its MERGE has a nifty extension IF NOT MATCHED BY SOURCE which allows you to DELETE in addition to INSERT and UPDATE.
Here's a simple example (e.g. omitting referential integrity constraints):
CREATE TABLE EmployeeDepartments
(
EmployeeID INTEGER NOT NULL,
DepartmentID INTEGER NOT NULL,
UNIQUE (DepartmentID, EmployeeID)
);
INSERT INTO EmployeeDepartments (EmployeeID, DepartmentID)
VALUES (1, 1),
(1, 2);
Say after editing you place the values in a staging table:
CREATE TABLE StagingTable
(
EmployeeID INTEGER NOT NULL,
DepartmentID INTEGER NOT NULL,
UNIQUE (DepartmentID, EmployeeID)
);
INSERT INTO StagingTable (EmployeeID, DepartmentID)
VALUES (1, 1),
(1, 3);
In plain English, row {1, 3} will be inserted, row {1, 2} will be deleted and row {1, 1} will remain:
MERGE INTO EmployeeDepartments
USING StagingTable AS S1
ON EmployeeDepartments.EmployeeID = S1.EmployeeID
AND EmployeeDepartments.DepartmentID = S1.DepartmentID
WHEN NOT MATCHED THEN
INSERT (EmployeeID, DepartmentID)
VALUES (EmployeeID, DepartmentID)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;