SQL Server update table with loop columns - sql-server

I want update a few interdependent tables that each have 100 columns. A simplified version of what I'm trying to do is:
Update a
Set a.[2] = b.[1]*c.[mult]
from table1 a join table2 b on a.[id] = b.[id]
join table3 c on a.[id] = c.[id]
Update b
Set b.[2] = a.[2]*d.[mult]
from table2 b join table1 b on a.[id] = a.[id]
join table4 d on b.[id] = d.[id]
And then loop it for column 3, 4, 5, ..., 100 for table a and table b. I'm new to dynamic SQL and reading a few existing posts on similar topic doesn't solve my question, especially in this case table1 and table2 depend on each other.
Thanks a lot for the help!

If you have multiple columns to update, you can do them all at once with the same update statement. You have to list each one.
Update a
Set a.[2] = b.[1]*c.[mult],
a.[3] = b.[2]*c.[mult],
a.[4] = b.[3]*c.[mult],
a.[5] = b.[4]*c.[mult],
// etc.
a.[100] = b.[99]*c.[mult]
from table1 a join table2 b on a.[id] = b.[id]
join table3 c on a.[id] = c.[id]
Update b
Set b.[2] = a.[2]*d.[mult],
b.[3] = a.[3]*d.[mult],
b.[4] = a.[4]*d.[mult],
b.[5] = a.[5]*d.[mult],
// etc.
b.[100] = a.[100]*d.[mult]
from table2 b join table1 b on a.[id] = a.[id]
join table4 d on b.[id] = d.[id]
However, if you're trying to number your columns and access them by index, then your table structure is poorly designed. Perhaps your tables should have a row for each index value and ID. This allows you to select or join by ID and index. For example,
Create Table table1
(
[id] int,
[index] int,
[value] int,
Primary Key ([id], [index])
)
Create Table table2
(
[id] int,
[index] int,
[value] int,
Primary Key ([id], [index])
)
Then you can join them like this:
Update a
Set a.[value] = b.[value]*c.[mult]
from table1 a join table2 b on a.[id] = b.[id] and a.[index] = b.[index]
join table3 c on a.[id] = c.[id]

Related

Combining subselects in SQL query

How can I simplify this query by combining the subselects?
SELECT *
FROM table
WHERE id1 IN (SELECT id1 FROM table WHERE [keyid] = 123)
AND id2 IN (SELECT [id2] FROM table WHERE [keyid] = 123)
I naively tried:
SELECT *
FROM table
WHERE id1 = t.id1
AND id2 = t.id2
IN (SELECT id1, id2 FROM table WHERE keyid = 123) AS t
There is no real need to rewrite your query, it is fine as-is. You could rewrite the subqueries using exists logic:
SELECT t1.*
FROM yourTable t1
WHERE
EXISTS (SELECT 1 FROM yourTable t2 WHERE t2.id1 = t1.id1 AND t2.keyid = 123) AND
EXISTS (SELECT 1 FROM yourTable t3 WHERE t3.id2 = t1.id2 AND t3.keyid = 123);
The exists logic would let SQL Server stop scanning your table as soon as it finds a single match. This might mean improved performance over the version you currently have.
If you wanted to rewrite using a series of self joins, here is what you could try:
SELECT DISTINCT t1.*
FROM yourTable t1
INNER JOIN yourTable t2 ON t2.id1 = t1.id1
INNER JOIN yourTable t3 ON t3.id2 = t1.id2
WHERE t2.keyid = 123 AND t3.keyid = 123;
From your tablenames, I assume that both IN Clauses refer to same table and refer to same key field.
SELECT t1.* FROM Table AS t1
INNER JOIN
(
SELECT Id1, Id2 FROM Table WHERE keyid = 123
) as t2
ON t1.id1 = t2.id1 AND t1.id2 = t2.id2

how to Join five Tables with one another dependency in SQL

I want to join five tables in SQL server. The sequence as given below. Logic should be
Table1 >>>>Key : ID >>>> Table_A & Table_B (If Table1.Status = ABC then Table_A else Table_B ) >>> Key : NUMBER >>> Table2 >>> Key : Number + Item_No >>> Table3
Please help if below code could work.
SELECT * FROM
TABLE1
LEFT JOIN (CASE WHEN status = 'ABC' THEN Table_A ELSE Table_B END ) X ON (Table1.ID = X.ID)
LEFT JOIN Table2 ON (X.NUMBER = Table2.NUMBER)
LEFT JOIN Table3 ON (Table3.CONCAT(NUMBER + Item_No) = Table2.CONCAT(NUMBER + Item_No))
SELECT Q.*, T2.ItemNo, T2.Product, T3.Connection
FROM (
SELECT T1.ID, CASE WHEN T1.Status = 'ABC'
THEN TA.Number
ELSE TB.Number
END as Number
FROM Table1 T1
LEFT JOIN TableA TA
ON T1.ID = TA.ID
LEFT JOIN TableB TB
ON T1.ID = TB.ID
) as Q
JOIN Table2 T2
ON Q.Number = T2.Number
JOIN Table3 T3
ON T2.ItemNo = T3.ItemNo

SQL Server insert new rows ONLY based on multiple columns

I searched in SO but couldn't find anything for my purpose. I need to insert unique rows ONLY from one table into another. I have:
table1
id name bookid bookname start_date end_date rel_date rel_id
1 horror 1221 rockys 04/01/2016 04/30/2016 05/01/2016 4545
2 horror 1331 elm 04/01/2016 04/30/2016 05/01/2016 5656
table2
id name bookid bookname start_date end_date rel_date rel_id
1 horror 1221 rockys 04/01/2016 04/30/2016 05/01/2016 4545
2 horror 1441 elm 04/01/2016 04/30/2016 05/01/2016 5656
I need to insert into table1 the row with id = 2 in table2 AND also delete the row with id = 2 from table1, because bookid is different even though the rest of the columns match.
I tried following:
insert into table1
select * from table2
where not exists (select * from table2 where table1.id = table2.id
and table1.name = table2.name and table1.bookid = table2.bookid and
table1.bookname = table2.bookname and table1.start_date = table2.start_date
and table1.end_date = table2.end_date and table1.rel_date = table2.rel_date
and table1.rel_id = table2.rel_id)
Any way I can do all of this in one sql block?
In theory the following merge statement should achieve what you are looking for.
MERGE table1 [Target]
USING table2 [Source]
ON ([Target].[name] = [Source].[name]
AND
[Target].[bookname] = [Source].[bookname]
AND
[Target].[start_date] = [Source].[start_date]
AND
[Target].[end_date] = [Source].[end_date]
AND
[Target].[rel_date] = [Source].[rel_date]
AND
[Target].[rel_id] = [Source].[rel_id]
)
WHEN MATCHED AND ([Target].[bookid] <> [Source].[bookid]) THEN
UPDATE
SET [Target].[name] = [Source].[name]
,[Target].[bookid] = [Source].[bookid]
,[Target].[bookname] = [Source].[bookname]
,[Target].[start_date] = [Source].[start_date]
,[Target].[end_date] = [Source].[end_date]
,[Target].[rel_date] = [Source].[rel_date]
,[Target].[rel_id] = [Source].[rel_id]
WHEN NOT MATCHED THEN
INSERT(
[name]
,[bookid]
,[bookname]
,[start_date]
,[end_date]
,[rel_date]
,[rel_id]
)
VALUES
(
[Source].[name]
,[Source].[bookid]
,[Source].[bookname]
,[Source].[start_date]
,[Source].[end_date]
,[Source].[rel_date]
,[Source].[rel_id]
);
Note that there are some risks and limitations to this approach. If your [id] column has a uniqueness constraint, then it should be set as an identity column otherwise you will run into uniqueness violation errors. Also if [id] column value in table1 is different to [id] column in table2 then merge statement will keep the original [id] value from table1.
Basically this query simply updates your existing record in table1 with the matching record in table2 and insert new records from table2 into table1 if they don’t already exists.
All you should need to achieve your objective is this:
UPDATE T1
SET T1.bookid = T2.bookid
FROM Table1 T1
JOIN Table2 T2
ON T1.ID = T2.ID
However, to answer the question exactly as it was asked:
DELETE T1
FROM Table1 T1
JOIN Table2 T2
ON T1.ID = T2.ID
AND T1.bookid <> T2.bookid
INSERT INTO Table1
SELECT id, name, bookid, bookname, start_date, end_date, rel_date, rel_id
FROM Table2 T2
LEFT OUTER JOIN Table1 T1
ON T1.ID = T2.ID
AND T1.bookid = T2.bookid
WHERE T1.id IS NULL
Note that if your ID fields aren't unique, you'll need to add other conditions to the ON clauses.
If you are just concerned about updating the bookid value from table2, you can change the value of bookid with the below query
UPDATE t1 SET t1.bookid = t2.bookid
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id
If you think your id column is not unique in two tables, you might need to consider adding other matching columns in the JOIN.

Inner join then full join among the matched records

I have two tables:
declare #Table1 as table (id int, value CHAR(1))
declare #Table2 as table (id int, value CHAR(1))
INSERT #Table1
VALUES (1, 'A'),
(1, 'B'),
(3, 'A')
INSERT #Table2
VALUES(1, 'A'),
(1, 'C'),
(2, 'A')
I want to join these two tables so that at the end I should be able to produce this result:
id value id value
1 A 1 A
1 B NULL NULL
NULL NULL 1 C
I'm sorry for inadequate explanation (I mean no explanation at all). What I am trying to do here is (something like) to make inner join for the id columns (I mean take the records which are common on both sets over the "id" column) then look at the value columns and compare them inside the boundaries of this common set.
I hope I could describe what I was trying to do.
Hope this will work
SELECT distinct t1_id as id, t1_value as value , t2_id as id , t2_value as value
FROM (SELECT t1.id as t1_id, t1.value as t1_value from #Table1 t1 INNER JOIN #Table2 t2 on t1.id = t2.id) as A
FULL OUTER JOIN
(SELECT t2.id as t2_id, t2.value as t2_value from #Table1 t1 INNER JOIN #Table2 t2 on t1.id = t2.id) as B
on A.t1_value = B.t2_value
ORDER BY t1_id desc
Basically, What I am doing is outer joining the inner set (which is inner join on id column) on value column of inner set.
What do I win?
SELECT c.id,c.value,d.id,d.value
FROM
#Table1 c
full join
#Table2 d
on c.id = d.id and c.value = d.value
WHERE exists
(
SELECT a.id
FROM
#Table1 a
INNER JOIN
#Table2 b
ON a.id = b.id and a.id = c.id or d.id = a.id
)
You can do this with a full outer join and by pre-filtering the tables:
select a.id as a_id, a.value as a_value,
b.id as b_id, b.value as b_value
from (select *
from tablea a
where a.id = 1
) a full outer join
(select *
from tableb b
where b.id = 1
) b
on a.id = b.id and a.value = b.value;

How to update and insert with list of values in sql

I get a list of values from the select query. From the list, I am checking whether the items in the list is available in the table. If the values exist, I need to update the values else Insert the list into the Table.
With the list, I can insert the list of values in the table.
How to check and update the list in sql.
My Query :
WITH pq AS
(
SELECT A.[ProductId] ,A.[Quantity],A.[OrderId],D.[ProductName],E.[SpecialPrice],E.[SpecialPrice]*A.[Quantity] AS SPrice FROM [Table1] A
LEFT JOIN [Table2] B ON A.[OrderId] = B.[OrderId] INNER JOIN [Table3] D
ON A.[ProductId] = D.[ProductId] INNER JOIN [Table4] E
ON A.[ProductId] = E.[ProductId] WHERE B.[CustomerId] = 1
AND A.[OrderId] = 77
)
IF (EXISTS(SELECT [ProductId] FROM [Table5] WHERE [ProductId] = A.[ProductId]))
BEGIN
UPDATE [Table5]
SET [Quantity] = A.[Quantity]
WHERE B.[CustomerId] = 1 AND [ProductId] = A.[ProductId]
END
ELSE
BEGIN
INSERT INTO [Table5]
([ProductId],[ProductName],[Quantity],[Price],[TotalAmount])
SELECT
[ProductId],[ProductName],[Quantity],[SpecialPrice],SPrice
FROM pq;
END
Any suggestions will be greatly helpful.
EDIT : SELECT QUERY RESULT
ProductId Quantity
65 2
64 1
Assuming you're on SQL Server 2008 or above, the MERGE statement will solve your problem:
MERGE Table5 TRG
USING (
SELECT
A.ProductId,
A.Quantity,
A.OrderId,
D.ProductName,
E.SpecialPrice,
(E.SpecialPrice * A.Quantity) SPrice
FROM Table1 A
LEFT JOIN Table2 B ON A.OrderId = B.OrderId
INNER JOIN Table3 D ON A.ProductId = D.ProductId
INNER JOIN Table4 E ON A.ProductId = E.ProductId
WHERE
B.CustomerId = 1
AND A.OrderId = 77
) SRC
ON TRG.ProductID = SRC.ProductID
WHEN MATCHED THEN
UPDATE SET TRG.Quantity = SRC.Quantity
WHEN NOT MATCHED BY TARGET THEN
INSERT (
ProductId
, ProductName
, Quantity
, Price
, TotalAmount
)
VALUES (
SRC.ProductId
, SRC.ProductName
, SRC.Quantity
, SRC.SpecialPrice
, SRC.SPrice)
;
You can move the SELECT query out to a CTE for legibility like you did in your example.

Resources