Insert when NOT matched - T/SQL - sql

I have 3 tables with same 5 columns (+ 1 flag column in T2 which we will use later...let's focus on 5 columns for this example).
T1, T2, and T3.
1st column in all three tables are Key Columns.
Let's say there are 5 records in T1 and T2.
4 records in T1 and T2 match for all columns.
5th record has 4 matching columns (1 key + 3 non-key). This means, T1 and T2 has 1 non-matching non-key column for the 5th record.
I want to do nothing with the first 4 columns
I want to insert the 5th column from T2 to T3 and update the 6th column of T2 to TRUE.
How does one go about doing this? Merge query won't work as it works with 2 tables only as far as I know...correct me if I am wrong.
Just a note: these tables have actually over 100 columns (same columns) sooo...hehe
ThanX
UPDATE: I wish to still pass the values for the first 4 columns from T2 to T3...not just the column that changed.

-- Not tuned to any particular syntax, may need to be tweaked.
T1([a],b,c,d,e);
T2([a],b,c,d,e,f);
T3([a],b,c,d,e);
---------
-- SQL --
---------
BT;
INSERT INTO T3
SELECT
T2.a,
CASE WHEN (T1.b <> T2.b) THEN T2.b ELSE null,
CASE WHEN (T1.c <> T2.c) THEN T2.c ELSE null,
CASE WHEN (T1.d <> T2.d) THEN T2.d ELSE null,
CASE WHEN (T1.e <> T2.e) THEN T2.e ELSE null
FROM
T1,
T2
WHERE T1.a = T2.a
AND (
T1.b <> T2.b
OR T1.c <> T2.c
OR T1.d <> T2.d
OR T1.e <> T2.e
);
UPDATE T2
SET T2.f = true
T1.a IN (
SEL T1.a
FROM T1, T2
WHERE T1.a = T2.a
AND (
T1.b <> T2.b
OR T1.c <> T2.c
OR T1.d <> T2.d
OR T1.e <> T2.e
)
);
ET; -- OR COMMIT depending on sytax
EXAMPLE DATA
-- BEFORE -- -- AFTER --
T1 T1
|[a]| b | c | d | e | |[a]| b | c | d | e |
|---+---+---+---+---| |---+---+---+---+---|
| 0 | 1 | 2 | 3 | 4 | | 0 | 1 | 2 | 3 | 4 |
| 1 | 2 | 3 | 4 | 5 | | 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 4 | 5 | | 1 | 2 | 3 | 4 | 5 |
| 3 | 4 | 5 | 6 | 7 | | 3 | 4 | 5 | 6 | 7 |
| 4 | 5 | 6 | 7 | 8 | | 4 | 5 | 6 | 7 | 8 |
T2 T2
|[a]| b | c | d | e | f | |[a]| b | c | d | e | f |
|---+---+---+---+---+---| |---+---+---+---+---+---|
| 0 | 1 | 2 | 3 | 4 | f | | 0 | 1 | 2 | 3 | 4 | f |
| 1 | 2 | 3 | 4 |-3 | f | | 1 | 2 | 3 | 4 |-3 | t |
| 2 | 3 | 4 | 5 | 6 | f | | 2 | 3 | 4 | 5 | 6 | f |
| 3 | 4 | 5 |-5 | 7 | f | | 3 | 4 | 5 |-5 | 7 | t |
| 4 | 5 | 6 | 7 | 8 | f | | 4 | 5 | 6 | 7 | 8 | f |
T3 T3
|[a]| b | c | d | e | |[a]| b | c | d | e |
|---+---+---+---+---| |---+---+---+---+---|
| 1 |nul|nul|nul|-3 |
| 3 |nul|nul|-5 |nul|

that solution is fine for five columns. How about 100 columns. You need dynamic T-SQL.
The below code is quite long and divided into 4 sections.
Section 1 - Create the database, test tables, and test data.
Section 2 - My user defined function for a delimited column list and Jeff Moden's split function.
Section 3 - Dynamic T-SQL, assumes first column is key and last column is flag. Uses EXCEPT command to find row differences.
Section 4 - Dynamic T-SQL, compares column 2 in T1 to column 2 in T2 with case statement. Continued for all columns. Insert into T3 for only rows that have a difference.
-- THIS CODE WILL WORK FOR A DYNAMIC LIST OF COLUMNS, NOT JUST 4! --
-- 1 - Create test tables w/data
-- the master db
use master;
go
-- create test database
create database test;
go
-- use test
use test;
go
-- create table 1
if (OBJECT_ID('t1') <> 0) drop table t1;
go
create table t1
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16) );
go
-- create table 2
if (OBJECT_ID('t2') <> 0) drop table t2;
go
create table t2
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16), flag1 int default 0);
go
-- create table 3
if (OBJECT_ID('t3') <> 0) drop table t3;
go
create table t3
( key1 int, col1 int, col2 int, col3 varchar(16), col4 varchar(16) );
go
-- Add 5 rows to t1
insert into t1 values (1, 2, 4, 'A', 'B');
insert into t1 values (2, 4, 8, 'C', 'D');
insert into t1 values (3, 6, 12, 'E', 'F');
insert into t1 values (4, 8, 16, 'G', 'H');
insert into t1 values (5, 10, 20, 'I', 'J');
select * from t1;
-- Add 5 rows to t2
insert into t2 (key1, col1, col2, col3, col4) values (1, 2, 4, 'A', 'B');
insert into t2 (key1, col1, col2, col3, col4) values (2, 4, 8, 'C', 'D');
insert into t2 (key1, col1, col2, col3, col4) values (3, 6, 12, 'E', 'F');
insert into t2 (key1, col1, col2, col3, col4) values (4, 8, 16, 'G', 'H');
insert into t2 (key1, col1, col2, col3, col4) values (5, 10, 20, 'I', 'K');
select * from t2;
--
-- 2A - Declare helper function for column name list
--
-- use test
use test;
go
-- remove function if it exists
if (OBJECT_ID('dbo.get_column_list') <> 0)
drop function get_column_list;
go
-- create new function
create function get_column_list (#schema_name sysname, #table_name sysname, #del_value varchar(10) = ',') returns varchar(max)
as
begin
-- nothing to do
if (#table_name is null) return null;
-- misc variables
declare #list varchar(max) = '';
-- select the changed items
select
#list += c.name + #del_value
from
sys.schemas s join sys.objects o on s.schema_id = o.schema_id
join sys.columns c on o.object_id = c.object_id
where
o.type = 'u' and
s.name = #schema_name and
o.name = #table_name
order by c.column_id;
-- remove last delimiter
select #list = substring(#list, 1, len(#list) - len(#del_value));
-- return a list
return #list
end;
go
--
-- 2B - spliter function from jeff moden
--
-- http://www.sqlservercentral.com/articles/Tally+Table/72993/
-- You download and install as TVF in [TEST] database
--
-- 3 - Find row differences using except
--
-- declare/initialize variables
declare #stmt1 varchar(max) = '';
-- column lists
declare #list1 varchar(max) = dbo.get_column_list ('dbo', 't1', ', ');
declare #list2 varchar(max) = dbo.get_column_list ('dbo', 't2', ', ');
-- key (first), flag (last)
declare #key1 sysname = left(#list1, charindex(',', #list1, 1) - 1);
declare #key2 sysname = reverse(left(reverse(#list2), charindex(',', reverse(#list2), 1) - 2));
-- make dynamic sql
select #stmt1 = '(select ' + #list1 + ' from t2 except select ' + #list1 + ' from t1) as d1';
select #stmt1 = 'update t2 set ' + #key2 + ' = 1 where ' + #key1 + ' in (select d1.' + #key1 + ' from ' + #stmt1 + ');';
-- debug line
--print #stmt1;
-- execute the sql
exec (#stmt1);
go
--
-- 4 - Find the columns differences using case
--
-- declare/initialize variables
declare #stmt varchar(max) = '';
-- column list
declare #list varchar(max) = dbo.get_column_list ('dbo', 't2', ',');
-- key (first), flag (last)
declare #key1 sysname = left(#list, charindex(',', #list, 1) - 1);
declare #key2 sysname = reverse(left(reverse(#list), charindex(',', reverse(#list), 1) - 1));
-- select the changed items (skip key & flag)
select
#stmt += 'case when s.' + Item + ' = t.' + Item + ' then null else t.' + Item + ' end as val_' + Item + ', '
from
DelimitedSplit8K (#list, ',')
where
ItemNumber not in
(
select min(ItemNumber) as skip_vals from DelimitedSplit8K (#list, ',')
union
select max(ItemNumber) as skip_vals from DelimitedSplit8K (#list, ',')
);
-- complete the statement
select #stmt = 'insert into t3 select t.' + #key1 + ',' + substring(#stmt, 1, len(#stmt) - 1) + ' from t1 as s join t2 as t on s.' + #key1 + ' = t.' + #key1 + ' where t.' + #key2 + ' = 1 ';
-- debug line
--print #stmt;
-- execute the sql
exec (#stmt);
go

Related

How to add items from another table based on a string aggregated column

I have 2 tables like this
[Table 1]:
|cust_id| tran |item |
| ------| -----|-------
| id1 | 123 |a,b,c |
| id2 | 234 |b,b |
| id3 | 345 |c,d,a,b|
[Table 2]:
| item. | value |
| ----- | ----- |
| a | 1 |
| b | 2 |
| c | 3 |
| d | 4 |
I want to create a target value by doing a lookup from table 2 in table 1 using big query.
|cust_id| tran.|item |target|
| ------| -----|------|------|
| id1 | 123 |a,b,c | 6
| id2 | 234 |b,b | 4
| id3 | 345 |c,d,a,b| 10
What can I try next?
Consider below simple approach
select *,
( select sum(value)
from unnest(split(item)) item
join table2
using (item)
) target
from table1
if applied to sample data in your question - output is
Try the following:
select t1.cust_id
, t1.tran
, t1.item
, sum(t2.value) as target
from table_1 t1
, UNNEST(split(t1.item ,',')) as item_unnested
LEFT JOIN table_2 t2
on item_unnested=t2.item
group by t1.cust_id
, t1.tran
, t1.item
With your data it gives the following:
Create a center table that splits the item column values on rows and join that table with table2.
Try following
--Cursor is used to split the item data row by row
--#temp is a temporary table
create table #temp (id varchar(10), trans varchar(10), item varchar(10), item1 varchar(10));
DECLARE #item varchar(10);
DECLARE #id varchar(10);
DECLARE #trans varchar(10);
DECLARE item_cusor CURSOR FOR
SELECT *
FROM table1;
OPEN item_cusor
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
WHILE ##FETCH_STATUS = 0
BEGIN
insert into #temp
SELECT #id,#trans,#item,*
FROM STRING_SPLIT (#item, ',')
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
END
CLOSE item_cusor;
DEALLOCATE item_cusor;
--select * from temp
select t.id as cust_id, t.trans,t.item , sum(cast(t2.value as int)) as target
from #temp t
JOIN table2 t2
on t.item1=t2.item
group by t.id, t.trans,t.item;
Cursors: https://www.c-sharpcorner.com/article/cursors-in-sql-server/
Temporary tables: https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/
String split function: https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql

Split Row and Paste to Different Tables Based on Column

I have a table like this. Table is populated each time an order is complete. One order can have one or many compartments.
+---------+-------+-------------+------+
| OrderID | Plant | Compartment | Qty |
+---------+-------+-------------+------+
| 91 | 12 | 1 | 2000 |
| 91 | 12 | 2 | 2000 |
| 91 | 12 | 3 | 2000 |
| 90 | 12 | 1 | 3000 |
| 89 | 12 | 1 | 5000 |
+---------+-------+-------------+------+
Please help write an SQL script that takes the above and splits it into two new tables like so:
Table 1
+---------+-------+
| OrderID | Plant |
+---------+-------+
| 91 | 12 |
| 90 | 12 |
| 89 | 12 |
+---------+-------+
Table 2
+---------+-------------+------+
| OrderID | Compartment | Qty |
+---------+-------------+------+
| 91 | 1 | 2000 |
| 91 | 2 | 2000 |
| 91 | 3 | 2000 |
| 90 | 1 | 3000 |
| 89 | 1 | 5000 |
+---------+-------------+------+
I've tried using the DISTINCT command as suggested;
SELECT * FROM table
WHERE [OrderID] = (SELECT DISTINCT OrderID from table where (COMPARTMENT = '1'))
Which returns the error;
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
If the script can keep track of already processed rows so as to avoid duplication each time it runs, that would be the icing on the cake.
This is how I'd do:
-- just for debugging, your table is my #table variable table
set nocount on
declare #table table (OrderId int, Plant int, Compartment int, Qty int)
insert into #table values (89, 12, 1, 5000)
insert into #table values (90, 12, 1, 3000)
insert into #table values (91, 12, 3, 2000)
insert into #table values (91, 12, 2, 2000)
insert into #table values (91, 12, 1, 2000)
insert into #table values (91, 12, 2, 3000)
set nocount off
--select * from #table
-- now here it comes selections:
if (exists (select *
from INFORMATION_SCHEMA.TABLES
where TABLE_SCHEMA = 'dbo' -- or your schema
and TABLE_NAME = 'THeader' -- or your header's table))
insert into THeader
select distinct t1.OrderId, t1.Plant
from #table t1
left join THeader t2 on t1.OrderId = t2.OrderId and t1.Plant = t2.Plant
where t2.OrderId is null
else
select distinct t1.OrderId, t1.Plant
into THeader
from #table t1
left join THeader t2 on t1.OrderId = t2.OrderId and t1.Plant = t2.Plant
where t2.OrderId is null
if (exists (select *
from INFORMATION_SCHEMA.TABLES
where TABLE_SCHEMA = 'dbo' -- or your schema
and TABLE_NAME = 'TChilds' -- or your childs's table))
insert into TChilds
select distinct t1.OrderId, t1.Compartment, t1.Qty
from #table t1
left join TChilds t2 on t1.OrderId = t2.OrderId and t1.Compartment = t2.Compartment and t1.Qty = t2.Qty
where t2.OrderId is null
else
select distinct t1.OrderId, t1.Compartment, t1.Qty
into TChilds
from #table t1
left join TChilds t2 on t1.OrderId = t2.OrderId and t1.Compartment = t2.Compartment and t1.Qty = t2.Qty
where t2.OrderId is null
-- just for debugging
select * from THeader
select * from TChilds
Edit: Even so, I see your master table as a child table, from where you must create Header's table. It's enough. I mean your Table can be my TChilds table, and key can be OrderId + Plant. (I don't know what means plant in this table)

SQL: select max(value) when change columns in table

Sorry if the title is confusing. I have a problem when Select from 2 table. I have 2 table like that.
Table 1: contains the column names of Table 2
+ Pkey | name1 | name2 +
+----------------------+
| 1 | a | b |
+----------------------+
| 2 | c | b |
Table 2: contains values
+ Pkey | a | b | c +
+----------------------+------+
| 1 | 10 | 2 | 7 |
+----------------------+------+
| 2 | 12 | 4 | 8 |
+----------------------+------+
| 3 | 8 | 2 | 4 |
+----------------------+------+
| 4 | 7 | 1 | 3 |
I want to get the max(value) from the table 2 and add when select table 1
Example: With first row of table 1 contains 2 values : a and b. From these two values, we refer to table 2 to calculated column a - column b is [8,8,6,6]. After getting the max value of this column is 8 and add when query table 1. Keep going with the next rows
Desired table:
+ Pkey | name1 | name2 | Desired column |
+----------------------+-------------------+
| 1 | a | b | 8 |
+----------------------+-------------------+
| 2 | c | b | 5 |
I have more than 10000 rows in table 1. I used function and It can not use dynamic in Function
One possible approach is to generate dynamic SQL:
-- Tables
CREATE TABLE #Table1 (
Pkey int,
name1 varchar(1),
name2 varchar(1)
)
INSERT INTO #Table1 (Pkey, name1, name2)
VALUES
(1, 'a', 'b'),
(2, 'c', 'b')
CREATE TABLE #Table2 (
Pkey int,
a int,
b int,
c int
)
INSERT INTO #Table2 (Pkey, a,b, c)
VALUES
(1, 10, 2, 7),
(2, 12, 4, 8),
(3, 8, 2, 4),
(4, 7, 1, 3)
-- Statement
DECLARE #stm nvarchar(max)
SET #stm = N''
SELECT #stm = #stm +
N'UNION ALL
SELECT
' + STR(Pkey) + ' AS Pkey,
''' + name1 + ''' AS name1,
''' + name2 + ''' AS name2, ' +
'PkeyMax = (SELECT MAX(' + name1 + ' - ' + name2 + ') FROM #Table2) '
FROM #Table1
SELECT #stm = STUFF(#stm, 1, 10, '')
-- Execution
EXEC (#stm)
Output:
Pkey name1 name2 PkeyMax
1 a b 8
2 c b 5
This gets the results you want, since there are few fields, makes sense to use CASE to get the ones you want (in order to avoid building dynamic SQL)
SELECT pkey,name1,name2,max(dif) FROM
(SELECT t1.pkey, t1.name1, t1.name2,
case when t1.name1 ='a' then t2.a
when t1.name1 ='b' then t2.b
when t1.name1 ='c' then t2.c
end
-
case when t1.name2 ='a' then t2.a
when t1.name2 ='b' then t2.b
when t1.name2 ='c' then t2.c
end dif
FROM Table1 t1 , Table2 t2) IQ
GROUP BY IQ.pkey, IQ.name1, IQ.name2

Splitting dynamically SQL columns into multiple columns based on a different column value

I am trying to convert dynamically a table like this:
+----+---------+-------+
| ID | Subject | Users |
+----+---------+-------+
| 1 | Hi! | Anna |
| 2 | Hi! | Peter |
| 3 | Try | Jan |
| 4 | Try | Peter |
| 5 | Try | Jan |
| 6 | Problem | Anna |
| 7 | Problem | José |
| 8 | Test | John |
| 9 | Test | John |
| 10 | Hi! | Anna |
| 11 | Hi! | José |
| 12 | Hi! | Anna |
| 13 | Hi! | Joe |
+----+---------+-------+
Into something like that:
+----+---------+-------+-------+-------+-------+
| ID | Subject | User1 | User2 | User3 | User4 |
+----+---------+-------+-------+-------+-------+
| 1 | Hi! | Anna | Peter | José | NULL |
| 2 | Try | Jan | Peter | NULL | NULL |
| 3 | Problem | Anna | José | NULL | NULL |
| 4 | Test | John | NULL | NULL | NULL |
+----+---------+-------+-------+-------+-------+
I have been reading the following links, but they are thought for splitting a column into a predefined number of columns:
Splitting SQL Columns into Multiple Columns Based on Specific Column Value
Split column into two columns based on type code in third column
I would need to split it dinamically depending on the content of the table.
SQL:
--【Build Test Data】
create table #Tem_Table ([ID] int,[Subject] nvarchar(20),[Users] nvarchar(20));
insert into #Tem_Table ([ID],[Subject] ,[Users]) values
('1','Hi!','Anna')
,('2','Hi!','Peter')
,('3','Try','Jan')
,('4','Try','Peter')
,('5','Try','Jan')
,('6','Problem','Anna')
,('7','Problem','José')
,('7','Test','John')
,('9','Test','John')
,('10','Hi! ','Anna')
,('11','Hi! ','José')
,('12','Hi! ','Anna')
,('13','Hi! ','Joe')
;
--STEP 1 distinct and ROW_NUMBER
with distinct_table as (
select [Subject],[Users]
,ROW_NUMBER() OVER (PARTITION BY [Subject] order by [Users]) [rank]
from (
select distinct [Subject],[Users] from #Tem_Table
) T00
)
--STEP 2 Group by row_count
,group_table as (
select [Subject]
from distinct_table T
group by [Subject]
)
--STEP 3 Use Left Join and Rank
select
T.[Subject],T1.[Users] as User1, T2.[Users] as User2 , T3.[Users] as User3, T4.[Users] as User4
from group_table T
left join distinct_table T1 on T.[Subject] = T1.[Subject] and T1.[rank] = 1
left join distinct_table T2 on T.[Subject] = T2.[Subject] and T2.[rank] = 2
left join distinct_table T3 on T.[Subject] = T3.[Subject] and T3.[rank] = 3
left join distinct_table T4 on T.[Subject] = T4.[Subject] and T4.[rank] = 4
order by [Subject];
result:
-------------------- -------------------- -------------------- -------------------- --------------------
Hi! Anna Joe José Peter
Problem Anna José NULL NULL
Test John NULL NULL NULL
Try Jan Peter NULL NULL
Update the Dynamic version :
--STEP 1 distinct and ROW_NUMBER
SELECT * into #distinct_table from (
select [Subject],[Users]
,ROW_NUMBER() OVER (PARTITION BY [Subject] order by [Users]) [rank]
from (
select distinct [Subject],[Users] from #Tem_Table
) T00
)T;
--STEP 2 Group by row_count
SELECT * into #group_table from (
select [Subject] ,count(1) [count]
from #distinct_table T
group by [Subject]
)T;
--Use Exec
DECLARE #select_sql AS NVARCHAR(MAX) = ' select T.[Subject] ',
#join_sql AS NVARCHAR(MAX) = ' from #group_table T ',
#max_count INT = (SELECT max([count]) FROM #group_table),
#temp_string NVARCHAR(5),
#temp_string_addone NVARCHAR(5)
;
DECLARE #index int = 0 ;
WHILE #index < #max_count
BEGIN
sELECT #temp_string = Convert(nvarchar(10),#index);
sELECT #temp_string_addone = Convert(nvarchar(10),#index+1);
select #select_sql = #select_sql + ' , T'+#temp_string_addone+'.[Users] as User'+#temp_string_addone+' '
select #join_sql = #join_sql + 'left join #distinct_table T'+#temp_string_addone+' on T.[Subject] = T'+#temp_string_addone+'.[Subject] and T'+#temp_string_addone+'.[rank] = '+#temp_string_addone+' ';
SET #index = #index + 1;
END;
EXEC (#select_sql
+ #join_sql
+' order by [Subject]; ')
;
CREATE TABLE mytable
([ID] int, [Subject] varchar(7), [Users] varchar(5))
;
INSERT INTO mytable
([ID], [Subject], [Users])
VALUES
(1, 'Hi!', 'Anna'),
(2, 'Hi!', 'Peter'),
(3, 'Try', 'Jan'),
(4, 'Try', 'Peter'),
(5, 'Try', 'Jan'),
(6, 'Problem', 'Anna'),
(7, 'Problem', 'José'),
(8, 'Test', 'John'),
(9, 'Test', 'John'),
(10, 'Hi!', 'Anna'),
(11, 'Hi!', 'José'),
(12, 'Hi!', 'Anna'),
(13, 'Hi!', 'Joe')
;
select distinct subject,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 0 rows fetch next 1 row only) user1,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 1 rows fetch next 1 row only) user2,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 2 rows fetch next 1 row only) user3,
(select users from (
select distinct users from mytable where subject=m.subject) a order by users offset 3 rows fetch next 1 row only) user4
from mytable m
you can use below dynamic query to get the result-
create table test_Raw(ID int ,Subject varchar(100), Users varchar(100))
insert into test_Raw
values (1,' Hi!','Anna'),
(2,' Hi!','Peter'),
(3,'Try','Jan'),
(4,'Try','Peter'),
(5,'Try','Jan'),
(6,'Problem','Anna'),
(7,'Problem','José'),
(8,'Test','John'),
(9,'Test','John'),
(10,' Hi!','Anna'),
(11,' Hi!','José'),
(12,' Hi!','Anna'),
(13,' Hi!','Joe')
--select * from test_Raw
select dense_RANK() over( order by Subject) Ranking1, dense_RANK() over(partition by Subject order by users) Ranking2 , Subject , Users
into test
from test_Raw
group by Subject , Users
order by 3
declare #min int , #mx int , #Select nvarchar(max) , #from nvarchar(max) , #vmin varchar(3)
select #min= 1 , #mx = MAX(Ranking2) , #Select= 'select ' , #from = ' from test t1 ' , #vmin = '' from test
while (#min<=#mx)
begin
select #vmin = CAST(#min as varchar(3))
select #Select = #Select + CASE WHEN #min = 1 THEN 't1.Ranking1 as ID , t1.Subject , t1.Users AS User1 ' ELSE ',t' +#vmin+'.Users as User'+#vmin END
select #from = #from + CASE WHEN #min = 1 THEN '' ELSE ' left join test t'+#vmin + ' on t1.Ranking1 = t' + #vmin + '.Ranking1 and t1.Ranking2 + ' + cast (#min-1 as varchar(10)) + ' = t'+#vmin+'.Ranking2' END
set #min = #min + 1
end
select #Select = #Select + #from + ' where t1.Ranking2 = 1'
exec sp_executesql #Select

Swap column value of same table in single SQL query

I have requirement to update column value of two rows with different keys. Constraint is that i want to do this in single query.
For example:
Coll1 Coll2
---------------
A 1
B 2
C 3
Should be like
Coll1 Coll2
--------------
A 3
B 2
C 1
using a case expression:
update t
set Coll2 = case when Coll1 = 'A' then 3 else 1 end
where Coll1 in ('A','C')
rextester demo: http://rextester.com/HUBDAP9516
returns:
+-------+-------+
| Coll1 | Coll2 |
+-------+-------+
| A | 3 |
| B | 2 |
| C | 1 |
+-------+-------+
update for a parameterized version:
declare #key1 char(1) = 'A';
declare #key2 char(1) = 'C';
update t
set t.Coll2 = x.Coll2
from t
inner join t x
on t.Coll1 <> x.Coll1
and t.Coll1 in (#key1,#key2)
and x.Coll1 in (#key1,#key2)
rextester demo: http://rextester.com/PKQSAV63963
returns:
+-------+-------+
| Coll1 | Coll2 |
+-------+-------+
| A | 3 |
| B | 2 |
| C | 1 |
+-------+-------+
Perhaps you mean a single transaction. Either way, I don't understand why--but since that is what you want, here's an easy way.
declare #table table (Col1 char(1), Col2 int)
insert into #table
values
('A',1),
('B',2),
('C',3)
update #table
set
Col2 = case
when Col1 = 'A' then 3
when Col1 = 'C' then 1
end
where Col1 in ('A','C')
select * from #table
BEGIN TRANSACTION
UPDATE t SET Coll2 = 3 WHERE Coll1 = 'A'
UPDATE t SET Coll2 = 1 WHERE Coll1 = 'C'
COMMIT
I'd like to try the following answer without hard-code col2
create table #t (col1 char(301), col2 int);
go
insert into #t (col1, col2)
values ('A', 1), ('B', 2), ('C', 3)
; with c as (
select col1, col2
from #t
)
update t
set t.col2 = c.col2
from #t t
inner join c
on abs(ascii(t.col1) - ascii(c.col1))=2
select * from #t
This is a generic solution where you have values to switch as a parameter or as a subquery.
It also works con char data, but need some tweaking on string manipulation.
declare #table table (Col1 char(1), Col2 int)
insert into #table
values
('A',1),
('B',2),
('C',3)
declare #swap1 char='A'
declare #swap2 char='C'
update #table
set col2 = (select sum(col2) from #table
where col1 in (#swap1,#swap2))-col2
where col1 in (#swap1,#swap2)