Sql query regarding foreign key dependency - sql

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

Related

SQL to Mongo query

I am looking to fetch the records from my mongo db which can be extracted from MySQL using a query like this:
select * from tableA where col1 between
(select col1 from tableA where col1 >= 0 and col2 = 'A001') and
(select col1 from tableA where col1 <= 1000 and col2 = 'A008')
In other words, I need to find the data between the records which match the queries for between.
Dataset:
create table tableA (
col1 int,
col2 varchar(255)
);
insert into tableA values(1, "A001");
insert into tableA values(2, "A002");
insert into tableA values(3, "A003");
insert into tableA values(4, "A004");
insert into tableA values(5, "A005");
insert into tableA values(6, "A006");
insert into tableA values(7, "A007");
insert into tableA values(8, "A008");
(Above query tested on MariaDB database)

How to update date in table based on two criteria from a select

I need to update a date in one table based on if an userID and planName are returned from a select off a different table.
Something like
UPDATE Table A
SET DATE = GETDATE()
WHERE userid AND planName IN (SELECT userid, planName From Table B)
The simplest method is to join these two tables in an UPDATE statement.
Try the following:
UPDATE [Table A]
SET DATE = GETDATE()
FROM [Table A] a
INNER JOIN [Table B] b on a.userid = b.userid and a.planName = b.planName
I think this is what you looking for:
UPDATE A
SET
A.DATE = GETDATE()
FROM TableA AS A
WHERE EXISTS
(
SELECT 1
FROM TableB AS B
WHERE B.userid = A.userid
AND B.planName = A.planName
);
this will update all the rows in your table A that have the exact combination(s) of userid and planName that exist in table B
so if Table A has the following:
userid planName
1 A
2 A
1 B
and Table B has the following
userid planName
1 A
1 B
it will only update the following in Table A:
userid planName
1 A
1 B
See if this helps...
-- some test data...
IF OBJECT_ID('tempdb..#TableA', 'U') IS NOT NULL
DROP TABLE #TableA;
CREATE TABLE #TableA (
UserID INT NOT NULL,
PlanName VARCHAR(5) NOT NULL,
SomeDate DATE NULL,
PRIMARY KEY CLUSTERED (UserID)
);
IF OBJECT_ID('tempdb..#TableB', 'U') IS NOT NULL
DROP TABLE #TableB;
CREATE TABLE #TableB (
UserID INT NOT NULL,
PlanName VARCHAR(5) NOT NULL,
PRIMARY KEY CLUSTERED (UserID, PlanName)
);
INSERT #TableA (UserID, PlanName) VALUES
(1, 'aaa'), (2, 'aab'), (3, 'abb'),
(4, 'aaa'), (5, 'aab'), (6, 'ccc');
INSERT #TableB (UserID, PlanName) VALUES
(1, 'aaa'), (1, 'abb'), (1, 'bbb'),
(2, 'aaa'), (2, 'abb'), (2, 'bbb'),
(3, 'aaa'), (3, 'abb'), (3, 'bbb'),
(4, 'aaa'), (4, 'abb'), (4, 'bbb'),
(5, 'aaa'), (5, 'abb'), (5, 'bbb'),
(6, 'aaa'), (6, 'abb'), (6, 'bbb');
--=========================================
-- check initial values...
SELECT * FROM #TableA ta;
SELECT * FROM #TableB tb;
-- written as a SELECT...
SELECT
*
FROM
#TableA ta
WHERE
EXISTS (SELECT 1 FROM #TableB tb WHERE ta.UserID = tb.UserID AND ta.PlanName = tb.PlanName);
-- written as an UPDATE...
UPDATE ta SET
ta.SomeDate = GETDATE()
FROM
#TableA ta
WHERE
EXISTS (SELECT 1 FROM #TableB tb WHERE ta.UserID = tb.UserID AND ta.PlanName = tb.PlanName);
-- check updated values...
SELECT * FROM #TableA ta;
This was able to get it:
WITH CTE (userid, planName)
AS (SELECT userid, planName From Table B)
UPDATE A
SET DATE = GETDATE()
FROM Table A
JOIN CTE B
ON B.userid = A.userid AND B.planName = A.planName

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

How do I remove all but some records based on a threshold?

I have a table like this:
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP
DROP TABLE #TEMP
I am trying to remove all but some records for those that have more than 3 names with the same id. Therefore, I am trying to get something like this:
id name
1 Adam
1 Copper
1 John
2 Jill
2 Jack
2 Lisa
3 Amy
I am not understanding how to write this query. I have gotten to the extent of preserving one record but not a threshold of records:
;WITH FILTER AS
(
SELECT id
FROM #TEMP
GROUP BY id
HAVING COUNT(id) >=3
)
SELECT id, MAX(name)
FROM #TEMP
WHERE id IN (SELECT * FROM FILTER)
GROUP BY id
UNION
SELECT id, name
FROM #TEMP
WHERE id NOT IN (SELECT * FROM FILTER)
Gives me:
1 Robert
2 Rocky
3 Amy
Any suggestions? Oh by the way, I don't care what records are preserved while merging.
You can do it using CTE
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP;
WITH CTE(N) AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY id ORDER BY id)
FROM #Temp
)
DELETE CTE WHERE N>3;
SELECT *
FROM #TEMP;
DROP TABLE #TEMP
I will change your select like this (not tested)
select name from #temp group by name having count(id) > 3
then you can implement your query in a delete statement using your select as a where clause
in inner query you can use row_number function over (partition by id)
and then in outer query you have to give condition like below
select id,name from (
SELECT id,name, row_number() over (partition by id order by 1) count_id FROM #test
group by id, name )
where count_id <=3
If i got your question right, you need to get rows when id occurrence 3 or more times
select t1.name,t1.id from tbl1 t1
inner join tbl1 t2 on t1.id = t2.id
group by t1.name, t1.id
having count(t1.id) > 2

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)
)