Combining rows in SQL Server against all other rows - sql

Say I have an table like this:
And I want to create a select which combines every non-null row against every other value such that I end up with:
etc, all the way up to 3 - 3 - 3
Can this be done in one select statement?

Since you want to combine values that are now on different rows, first you need to seperate them in subqueries (the with statements), then you can cross join these (cartesian product) to find all different combinations.
with
c1 as (select column1 from table where column1 is not null),
c2 as (select column2 from table where column2 is not null),
c3 as (select column3 from table where column3 is not null)
select *
from c1, c2, c3 -- no join condition returns all possible combinations

You can do it with two CROSS JOIN's:
DECLARE #tb AS TABLE
(
column1 INT
,column2 INT
,column3 INT
);
INSERT INTO #tb VALUES (1, NULL, NULL);
INSERT INTO #tb VALUES (2, NULL, NULL);
INSERT INTO #tb VALUES (3, NULL, NULL);
INSERT INTO #tb VALUES (NULL, 1, NULL);
INSERT INTO #tb VALUES (NULL, 2, NULL);
INSERT INTO #tb VALUES (NULL, 3, NULL);
INSERT INTO #tb VALUES (NULL, NULL, 1);
INSERT INTO #tb VALUES (NULL, NULL, 2);
INSERT INTO #tb VALUES (NULL, NULL, 3);
SELECT tb1.column1, tb2.column2, tb3.column3
FROM #tb tb1
CROSS JOIN #tb AS tb2
CROSS JOIN #tb AS tb3
WHERE tb1.column1 IS NOT NULL
AND tb2.column2 IS NOT NULL
AND tb3.column3 IS NOT NULL
ORDER BY tb1.column1, tb2.column2, tb3.column3;

Use cross join:
DECLARE #t table(col1 int, col2 int, col3 int)
INSERT #t values
(1, null, null),(2, null, null),(3, null, null),
(null, 1, null),(null, 2, null),(null, 3, null),
(null, null, 1),(null, null, 2),(null, null, 3)
SELECT t1.col1, t2.col2, t3.col3
FROM #t t1
CROSS JOIN #t t2
CROSS JOIN #t t3
WHERE t1.col1 is not null and t2.col2 is not null and t3.col3 is not null

You need to do a Cross Join here. Try this.
;WITH cte
AS (SELECT 1 cola,NULL colb, NULL colc
UNION
SELECT 2 cola,NULL colb,NULL colc
UNION
SELECT 3 cola,NULL colb,NULL colc
UNION
SELECT NULL cola,1 colb,NULL colc
UNION
SELECT NULL cola,2 colb,NULL colc
UNION
SELECT NULL cola,3 colb,NULL colc
UNION
SELECT NULL cola,NULL colb,1 colc
UNION
SELECT NULL cola,NULL colb,2 colc
UNION
SELECT NULL cola,NULL colb,3 colc)
SELECT *
FROM (SELECT a.cola
FROM cte a
WHERE cola IS NOT NULL) f
CROSS JOIN (SELECT b.colb
FROM cte b
WHERE colb IS NOT NULL) s
CROSS JOIN (SELECT c.colc
FROM cte c
WHERE colc IS NOT NULL) T

Related

Sql query regarding foreign key dependency

I have two tables, Table A and Table B. Both the table have the "Id" column. Table B is dependent (foreign key) on this "Id". So i want to retrieve the rows which are not present in B.
You seems want :
select a.*
from tablea a
where not exists (select 1 from tableb b where b.id = a.id);
This should work in all flavours of SQL:
select t1.*
from TableA t1
left join TableB t2
on t1.id = t2.id
where t2.id is null
CREATE TABLE TableA
(
ID INT,
[Name] Varchar(500)
)
Insert INTO TableA Values(1, 'James')
Insert INTO TableA Values(2, 'John')
Insert INTO TableA Values(3, 'Betty')
Insert INTO TableA Values(4, 'Sherlin')
CREATE TABLE TableB
(
TableBID INT,
ID INT,
Project Varchar(250)
)
Insert INTO TableB Values(1, 1, 'ABC')
Insert INTO TableB Values(2, 1, 'XYZ')
Insert INTO TableB Values(3, 2 , 'ASD')
Insert INTO TableB Values(4, 1, 'VGF')
Insert INTO TableB Values(5, 3, 'ABC')
Insert INTO TableB Values(6, 3, 'XYZ')
Insert INTO TableB Values(7, 2, 'FGH')
SELECT * FROM TableA a
WHERE exists (SELECT 1 FROM TableB b WHERE b.id = a.id);
OR
SELECT * FROM TABLEA a WHERE ID IN (SELECT ID FROM TableB);
DROP TABLE TABLEA
DROP TABLE TABLEB

concat a column fields of a table group by the fields of another table

I have two tables say t1 and t2 which join with testid.I need to concat val column of t2 if d1,d2 and id of table t1 is same.Please refer to the following tables.
CREATE TABLE #t1 (d1 varchar(100),d2 varchar(100),id int,testid int)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('p','q',1,101)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('r','s',2,102)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('p','q',1,103)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('r','s',1,104)
CREATE TABLE #t2 (testid int,val varchar(100))
INSERT INTO #t2 (testid,val) values (101,'x')
INSERT INTO #t2 (testid,val) values (102,'y')
INSERT INTO #t2 (testid,val) values (103,'z')
INSERT INTO #t2 (testid,val) values (104,'xx')
The result should be:
d1 d2 pid val
p q 1 x,z
r s 2 y
r s 1 xx
IF OBJECT_ID('tempdb.dbo.#t1') IS NOT NULL
DROP TABLE #t1
IF OBJECT_ID('tempdb.dbo.#t2') IS NOT NULL
DROP TABLE #t2
CREATE TABLE #t1 (d1 VARCHAR(100), d2 VARCHAR(100), id INT, testid INT)
INSERT INTO #t1 (d1, d2, id, testid)
VALUES ('p', 'q', 1, 101)
, ('r', 's', 2, 102)
, ('p', 'q', 1, 103)
, ('r', 's', 1, 104)
CREATE TABLE #t2 (testid INT, val VARCHAR(100))
INSERT INTO #t2 (testid, val)
VALUES (101, 'x')
, (102, 'y')
, (101, 'z')
, (104, 'xx')
SELECT *
FROM (
SELECT d1, d2, id, value = STUFF((
SELECT [text()] = ',' + val
FROM #t2
WHERE #t2.testid = #t1.testid
FOR XML PATH('')), 1, 1, '')
FROM #t1
) t
WHERE t.value IS NOT NULL
output -
d1 d2 id value
--- --- ---- ----------------
p q 1 x,z
r s 2 y
r s 1 xx

Updated SQL Conditional INSERT

I have a situation where I need to insert data from table1 to table2. Before insert check if a certain row already exist in the table2, if it does then just update col2, col4 of the row. If it doesn't exist then insert a new row.
I am using SQLSERVER 2008 R2. How could I achieve this?
The situation has changed a bit now. I need something like this.
DECLARE #table1 TABLE
(id int not null, ahccs int not null, info varchar(25), flag varchar(2))
DECLARE #table2 TABLE
(id int not null, ahccs int not null, info varchar(25), flag varchar(2))
INSERT INTO #table1
VALUES(1, 1223, 'et', 'X')
INSERT INTO #table1
VALUES(2, 321, 'et', 'X')
INSERT INTO #table1
VALUES(3, 134, 'et', 'X' )
INSERT INTO #table1
VALUES(4, 168, 'et', 'X' )
INSERT INTO #table1
VALUES(5, 123, 'et', 'X' )
INSERT INTO #table2
VALUES(1, 1223, 'dt', 'y' )
INSERT INTO #table2
VALUES(2, 456, 'dt', 'y' )
INSERT INTO #table2
VALUES(3, 123, 'dt', 'y' )
INSERT INTO #table2
VALUES(4, 193, 'dt', 'y' )
--SELECT * FROM #table1
SELECT * FROM #table2
MERGE
INTO #table2 t2
USING #table1 t1
ON t2.id = t1.id or t2.ahccs = t1.ahccs
WHEN NOT MATCHED THEN
UPDATE
SET flag = 'z'
INSERT VALUES (100, t1.ahccs, t1.info, 'l');
The two issues I am having are:
1) Merge doesn't support multiple steps, I believe.
2) Update is not allowed in WHEN NOT MATCHED case.
Please advise.
Thank You.
You need to use merge, it lets you match the data that you are trying to update or insert ("upsert") against the data that is currently in the table, and perform different actions based on the presence or absence of a match.
MERGE Stock S
USING Trades T ON S.Stock = T.Stock
WHEN MATCHED THEN
UPDATE SET Qty += Delta
WHEN NOT MATCHED THEN
INSERT VALUES (Stock, Delta);
This example is from here.
MERGE
INTO table2 t2
USING table1 t1
ON t2.id = t1.t2_id
WHEN NOT MATCHED THEN
INSERT
VALUES (t1.col1, t1.col2, ...)
WHEN MATCHED THEN
UPDATE
SET col2 = t1.col2,
col4 = t1.col4

Select rows with duplicate values in 2 columns

This is my table:
CREATE TABLE [Test].[dbo].[MyTest]
(
[Id] BIGINT NOT NULL,
[FId] BIGINT NOT NULL,
[SId] BIGINT NOT NULL
);
And some data:
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (1, 100, 11);
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (2, 200, 12);
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (3, 100, 21);
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (4, 200, 22);
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (5, 300, 13);
INSERT INTO [Test].[dbo].[MyTest] ([Id], [FId], [SId]) VALUES (6, 200, 12);
So I need 2 select query,
First Select FId, SId that like a distinct in both column so the result is:
100, 11
200, 12
100, 21
200, 22
300, 13
As you see the values of 200, 12 returned once.
Second query is the Id's of that columns whose duplicated in both FId, SId So the result is:
2
6
Does any one have any idea about it?
Standard SQL
SELECT
M.ID
FROM
( -- note all duplicate FID, SID pairs
SELECT FID, SID
FROM MyTable
GROUP BY FID, SID
HAVING COUNT(*) > 1
) T
JOIN -- back onto main table using these duplicate FID, SID pairs
MyTable M ON T.FID = M.FID AND T.SID = M.SID
Using windowing:
SELECT
T.ID
FROM
(
SELECT
ID,
COUNT(*) OVER (PARTITION BY FID, SID) AS CountPerPair
FROM
MyTable
) T
WHERE
T.CountPerPair > 1
First query:
SELECT DISTINCT Fid,SId
FROM MyTest
Second query:
SELECT DISTINCT a1.Id
FROM MyTest a1 INNER JOIN MyTest a2
ON a1.Fid = a2.Fid
AND a1.SId = a2.SId
AND a1.Id <> a2.Id
I cannot test them, but I think they should work...
first:
select distinct FId,SId from [Test].[dbo].[MyTest]
second query
select distinct t.Id
from [Test].[dbo].[MyTest] t
inner join [Test].[dbo].[MyTest] t2
on t.Id<>t2.Id and t.FId=t2.FId and t.SId=t2.SId
Part 1 is as mentioned above distinct.
This will resolve second part.
select id from [Test].[dbo].[MyTest] a
where exists(select 1 from [Test].[dbo].[MyTest] where a.[SId] = [SId] and a.[FId] = [FId] and a.id <> id)

Merging records based on a time difference?

I have the following table:
CREATE TABLE #TEMP (id int, name varchar(255), startdate datetime, enddate datetime)
INSERT INTO #TEMP VALUES(1, 'John', '2011-01-11 00:00:00.000','2011-01-11 00:01:10.000')
INSERT INTO #TEMP VALUES(2, 'John', '2011-01-11 00:00:20.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(3, 'John', '2011-01-11 00:01:40.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(4, 'Adam', '2011-01-11 00:00:40.000','2011-01-11 00:01:20.000')
INSERT INTO #TEMP VALUES(5, 'Adam', '2011-01-11 00:00:10.000','2011-01-11 00:01:30.000')
SELECT * FROM #TEMP
DROP TABLE #TEMP
I am trying to merge all records with the same name within a range of 60 seconds to each other to get the following:
John 2011-01-11 00:00:00.000 2011-01-11 00:01:10.000
John 2011-01-11 00:01:40.000 2011-01-11 00:01:50.000
Adam 2011-01-11 00:00:10.000 2011-01-11 00:01:20.000
Any suggestions on how to do this on a table with about 50K records? Currently, I managed to get to this:
SELECT * FROM #TEMP
CREATE TABLE #Merge(id1 int, id2 int)
INSERT INTO #Merge
SELECT id, uuid
FROM
(
SELECT t.id, u.uuid, t.name, t.startdate, t.enddate, u.ustartdate, u.uenddate,
(CASE WHEN (DATEDIFF(second, t.startdate, u.ustartdate) <= 60 AND DATEDIFF(second, t.startdate, u.ustartdate) >= 0) then 1 else 0 END) Flag
FROM #Temp t
INNER JOIN
(SELECT id AS uuid, name, startdate AS ustartdate, enddate AS uenddate
FROM #Temp) u
ON t.name = u.name AND t.startdate != u.ustartdate AND t.id != u.uuid
) w
WHERE Flag = 1
SELECT * FROM #Merge
-- Insert non-mergable records
CREATE TABLE #TEMP2 (id int, name varchar(255), membergroup varchar(255), startdate datetime, enddate datetime)
INSERT INTO #TEMP2
SELECT * FROM #TEMP
WHERE id NOT IN (SELECT id1 FROM #Merge UNION SELECT id2 FROM #Merge)
SELECT * FROM #TEMP2
Of course, I am not sure how to proceed from here. The #Merge table gives me rows that are to be merged. What I did was to insert non-mergable rows first into #Temp2 first.
EDIT:
Updated set of rows, just in case:
INSERT INTO #TEMP VALUES(1, 'John', 'A', '2011-01-11 00:00:00.000','2011-01-11 00:01:10.000')
INSERT INTO #TEMP VALUES(2, 'John', 'A', '2011-01-11 00:00:01.000','2011-01-11 00:01:10.000')
INSERT INTO #TEMP VALUES(3, 'John', 'B', '2011-01-11 00:00:20.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(4, 'John', 'C', '2011-01-11 00:01:40.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(5, 'John', 'C', '2011-01-11 00:01:50.000','2011-01-11 00:02:20.000')
INSERT INTO #TEMP VALUES(6, 'Adam', 'A', '2011-01-11 00:00:40.000','2011-01-11 00:01:20.000')
INSERT INTO #TEMP VALUES(7, 'Adam', 'B', '2011-01-11 00:00:10.000','2011-01-11 00:01:30.000')
INSERT INTO #TEMP VALUES(8, 'Adam', 'B', '2011-01-11 00:03:10.000','2011-01-11 00:04:30.000')
The code below manage's to show both merged rows (rows 1-2,4-5) and unique rows (row 3)
SELECT DISTINCT a.id,a.name,a.startdate,a.enddate
FROM temp a
LEFT JOIN temp b ON a.name = b.name AND a.id < b.id AND DATEDIFF(s,a.startdate,b.startdate)<=60
LEFT JOIN temp c ON c.name = a.name AND c.id < a.id AND DATEDIFF(s,c.startdate,a.startdate)<=60
WHERE (b.id IS NOT NULL OR c.id IS NULL) AND a.id <= COALESCE(c.id,a.id)
Given you haven't said how to use the 60 second interval and your sample code showed only a startdate comparison, here you go
SELECT
*
FROM
#Temp t1
CROSS APPLY
(SELECT TOP 1*
FROM #Temp t2
WHERE t1.name = t2.name AND DATEDIFF(second, t1.startdate, t2.startdate) < 60 AND t1.id < t2.id
ORDER BY id DESC
) t2x
Based on startdate only, row pairs 1/2 and 4/5 make it into the output. Row 3 doesn't so you'll have to explain why you added it.
That is, row id = 3 is not within 60 seconds of row 1 or 2 based on startdate. So it shouldn't be in the output.
This assumes that id and startdate are both increasing.
Edit, after chat:
SELECT
*
FROM
#Temp t1
CROSS APPLY
(SELECT TOP 1 *
FROM #Temp t2
WHERE t1.name = t2.name AND DATEDIFF(second, t1.startdate, t2.startdate) < 60 AND t1.id < t2.id
ORDER BY t2.id DESC
) t2x
UNION ALL
SELECT
t1.*, t1.*
FROM
#Temp t1
WHERE NOT EXISTS
(
SELECT
t1ZZ.id, t2xZZ.id
FROM
#Temp t1ZZ
CROSS APPLY
(SELECT TOP 1 *
FROM #Temp t2ZZ
WHERE t1ZZ.name = t2ZZ.name AND DATEDIFF(second, t1ZZ.startdate, t2ZZ.startdate) < 60 AND t1ZZ.id < t2ZZ.id
ORDER BY t2ZZ.id DESC
) t2xZZ
WHERE
t1.id IN (t1ZZ.id, t2xZZ.id)
)