MS SQL not exist where more columns are - sql

I have table 1 from which I need take and ad to table2 only rows which is not in table 2
Table 1
ID Name N T
A Bob 33 Y
B Eva 44 N
C John 47 Y
B Alex 44 N
D Bob 47 Y
Table 2
ID Name N T
A Bob 34 Y
B Alex 44 N
D Bob 47 Y
I try set up this type of version script but i get duplicity of whole table 1 + new rows
INSERT INTO TABLE_2
(ID , Name , N , T)
SELECT table1.ID, table1.Name, table1.N, table1.T
FROM TABLE_1 table1
WHERE NOT EXISTS(SELECT 1
FROM TABLE_2 table2
WHERE (table2.ID = table1.ID) and (table2.Name = table1.Name) and (table2.N = table1.N )AND (table2.T = table1.T))
Expect Result
A Bob 34 Y
B Alex 44 N
D Bob 47 Y
A Bob 33 Y
B Eva 44 N
C John 47 Y

One approach would be to an INSERT INTO ... SELECT with a select query identifying all records in table1 which do not completely match some record in table2.
INSERT INTO table2 (ID, Name, N, T)
SELECT t1.ID, t1.Name, t1.N, t1.T
FROM table1 t1
LEFT JOIN table2 t2
ON t1.ID = t2.ID AND
t1.Name = t2.Name AND
t1.N = t2.N AND
t1.T = t2.T
WHERE t2.ID IS NULL
Note that the logic here is that if even one column of a given record in table1 be not in agreement with a certain record in table2, then the join would fail, and all table2 columns would then come up NULL in the result set. The WHERE clause restricts to only such non matching records in table1.

You could join both tables with a left join.
All records from Table_1 who don't have a match with Table_2 have to be inserted. To check which record doesn't have a match you can simply use T2.ID IS NULL
INSERT INTO TABLE_2 (ID , Name , N , T)
SELECT T1.ID
,T1.Name
,T1.N
,T1.T
FROM TABLE_1 T1
LEFT JOIN TABLE_2 T2
ON T1.ID = T2.ID
AND T1.Name = T2.Name
AND T1.N = T2.N
AND T1.T = T2.T
WHERE T2.ID IS NULL

declare #Table1 table (ID varchar(100), Name varchar(100), N int, T varchar(100));
insert into #Table1 values
('A', 'Bob', 33, 'Y'),
('B', 'Eva', 44, 'N'),
('C', 'John', 47, 'Y'),
('B', 'Alex', 44, 'N'),
('D', 'Bob', 47, 'Y')
declare #Table2 table (ID varchar(100), Name varchar(100), N int, T varchar(100));
insert into #Table2 values
('A', 'Bob', 34, 'Y'),
('B', 'Alex', 44, 'N'),
('D', 'Bob', 47, 'Y')
insert into #Table2
select *
from #Table1 t1
where not exists (select *
from #Table2 t2
where t2.ID = t1.ID and t2.N= t1.N and t2.Name = t1.Name and t1.T = t2.T);

Related

count of row by row from another table holding some conditions on both tables in sql

There are two tables Table1 and Table2
A B C S
a 1 21 Summer
b 2 22 Summer
c 3 34 Summer
D E F S
a 1 21 Summer
d 5 22 Summer
f 2 34 Summer
I wanted to fetch all columns of Table first and count of column F from table second based on conditions such as column B OF table first is less than values of column E of table second.
I tried this query
select a.*,
(select count(F) from Table2 JOIN Table1 on table1.S=table2.S where table1.B<table2.E ) AS Cnt
from Table1 a
However it is giving me same count for all rows which is incorrect
I need count based on condition fulfilled.
This will work
DECLARE #T1 TABLE (A Varchar(10), B INT, C INT, S Varchar(10))
DECLARE #T2 TABLE (D Varchar(10), E INT, F INT, S Varchar(10))
INSERT INTO #T1 VALUES
('a', 1, 21,'Summer'),
('b', 2 ,22,'Summer'),
('c', 3, 34,'Summer')
INSERT INTO #T2 VALUES
('a', 1, 21,'Summer'),
('d', 5 ,22,'Summer'),
('f', 2 ,34,'Summer')
SELECT
T1.A,T1.B,T1.C,T1.S,
COUNT(T2.S) as Counts
FROM #T1 T1
left JOIN #T2 T2
ON T1.S = T2.S AND T1.B < T2.E
GROUP BY T1.A,T1.B,T1.C,T1.S
Output
A B C S Counts
a 1 21 Summer 2
b 2 22 Summer 1
c 3 34 Summer 1
select *,
(select count(F)
from T2
where T1.S = T2.S AND T1.B < T2.E
) as Cnt from T1
I think you just want a correlated subquery:
select a.*,
(select count(t2.F)
from Table2 t2
where a.S = t2.S and t1.B < t2.E
) as Cnt
from Table1 a

SQL Left JOINING 3 Tables

I have 1 Table:
Contacts (ID integer, Name text, ATT_ID integer)
My Table is filled with these values:
(1, 'Alice', 1)
(2, 'Bob', 1)
(3, 'Carol', 1)
(4, 'Dave', 4)
(5, 'Eve', 4)
(6, 'Frank', 6)
The goal is to join these Contacts ID with the paired ATT_ID.
This is my current SQL-Code:
SELECT t1.ID as ID, t1.Name , tt.Name , tt2.Name
FROM Contacts as t1
LEFT JOIN (
SELECT MIN(t2.ID), t2.Name, t2.ATT_ID FROM Contacts as t2
WHERE t2.ID <> t2.ATT_ID)
AS tt ON t1.ID = tt.ATT_ID
LEFT JOIN (
SELECT MAX(t3.ID), t3.Name, t3.ATT_ID FROM Contacts as t3
WHERE t3.ID <> t3.ATT_ID)
AS tt2 ON t1.ID = tt2.ATT_ID
WHERE t1.ID = t1.ATT_ID;
and my Result is:
Alice | Bob | null
Dave | null | Eve
Frank | null | null
But the desired result should look like this:
Alice | Bob | Carol
Dave | Eve | null
Frank | null | null
How can I accomplish this?
Assuming your RDBMS supports Window Functions...
This can be accomplished by generating a row number of for each sub group and only displaying the smallest row number.
This also assumes you have no more than 3 in each group.
The below is ORACLE specific but should work with MS SQL and Postgresql and DB2. It will not work with MySQL as window functions are not supported.
Note the with block as built will only work in ORACLE.
With contacts (ID, Name, ATT_ID) as (
Select 1, 'Alice', 1 from dual union all
Select 2, 'Bob', 1 from dual union all
Select 3, 'Carol', 1 from dual union all
Select 4, 'Dave', 4 from dual union all
Select 5, 'Eve', 4 from dual union all
Select 6, 'Frank', 6 from dual)
--FROM HERE ON should work if window functions supported.
Select * from (
Select T1.Name N1, T2.Name N2, T3.Name N3, Row_Number() Over (partition by T1.ATT_ID order by T1.ID) rn
FROM Contacts T1
LEFT JOIN Contacts T2
on T1.ATT_ID = T2.ATT_ID
and T1.ID < T2.ID
LEFT JOIN contacts T3
on T2.ATT_ID = T3.ATT_ID
and T2.ID < T3.ID
and T1.ID < T3.ID) B
WHERE RN =1

Update table in Sql

Table tblProductStock:
ID Name Qyt
1 X 50
2 Y 40
3 Z 30
Table tblStockMinus:
Id Name Qty
1 X 10
1 X 20
2 Y 30
3 Z 20
I want to update tblProductStock so that it will have:
ID Name Qyt
1 X 20
2 Y 10
3 Z 10
I have tried to use the following SQL request, but it didn't work correctly:
UPDATE ProductStock_Show
SET Quantity = ProductStock_Show.Quantity - ProductStock_Show_Minus.Quantity
FROM ProductStock_Show JOIN ProductStock_Show_Minus
ON ProductStock_Show_Minus.ProductId=ProductStock_Show.ProductId
This will give you required result.
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
You need to update this (but it depends in the RDBMS. This is for MS SQL Server)
Update t
set
t.qty=t3.qty from tblProductStock as t inner join
(
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
) as t3 on t.id=t3.id
DECLARE #Table1 TABLE
( ID int, Name varchar(1), Qyt int)
;
INSERT INTO #Table1
( ID , Name , Qyt )
VALUES
(1, 'X', 50),
(2, 'Y', 40),
(3, 'Z', 30)
;
DECLARE #Table2 TABLE
( Id int, Name varchar(1), Qty int)
;
INSERT INTO #Table2
( Id , Name , Qty )
VALUES
(1, 'X', 10),
(1, 'X', 20),
(2, 'Y', 30),
(3, 'Z', 20)
;
UPDATE #Table1 SET QYT =
t.Qyt - s from (
select
t.id,
t.Name,
t.Qyt ,
SUM(tt.Qty)S
FROM #Table1 t
INNER JOIN #Table2 tt
ON t.Name = tt.Name
GROUP BY t.id,t.Name,t.Qyt)T
SELECT * from #Table1

Finding unmatched rows of 2 tables in SQL

I have 2 tables with 3 columns that are suppose to have the same information.
I would like have a query that selects only the rows that don't have a complete row match. Below is an example of the 2 tables I would like to match:
Table 1
ID FPRICE FPRODUCT
1 1 A
2 2 B
3 3 C
4 4 D
5 5 F
Table 2
ID TPRICE TPRODUCT
1 1 A
2 2 B
3 3 C
4 5 D
6 6 E
Desired Output:
ID FPRICE FPRODUCT TPRICE TPRODUCT
4 4 D 5 D
5 5 F NULL NULL
6 NULL NULL 6 E
Easier to verify if we build some DDL and fillwith sample data, but I think this would do it. It takes a full join to find records with a partial match and then filters out records with a full match.
sqlfiddle.com
CREATE TABLE Table1 (ID INT, FPRICE INT, FPRODUCT CHAR(1))
INSERT INTO Table1 (ID,FPRICE,FPRODUCT) VALUES
(1, 1, 'A')
,(2, 2, 'B')
,(3, 3, 'C')
,(4, 4, 'D')
,(5, 5, 'F')
CREATE TABLE TABLE2 (ID INT, TPRICE INT, TPRODUCT CHAR(1))
INSERT INTO Table2 (ID,TPRICE,TPRODUCT) VALUES
(1, 1, 'A')
,(2, 2, 'B')
,(3, 3, 'C')
,(4, 5, 'D')
,(6, 6, 'E')
SELECT *
FROM Table1 t1
FULL JOIN
Table2 t2 ON t1.ID = t2.ID
--EDIT: remove to exactly match the desired output
--OR t1.FPRICE = t2.TPRICE
--OR t1.FPRODUCT = t2.TPRODUCT
WHERE NOT ( t1.ID = t2.ID
AND t1.FPRICE = t2.TPRICE
AND t1.FPRODUCT = t2.TPRODUCT)
OR ( COALESCE(t1.ID,t1.FPRICE,T1.FPRODUCT) IS NULL
OR COALESCE(t2.ID,t2.TPRICE,T2.TPRODUCT) IS NULL)
Use full join:
select *
from Table1 t1
full join Table2 t2 on t1.ID = t2.ID and
t1.FPRICE = t2.FPRICE /*and
t1.FPRODUCT = t2.FPRODUCT*/
where t1.ID is null or t2.ID is null
It looks like you want to match on the id's and then compare the values:
select t1.id, t1.fprice, t1.fproduct, t2.fprice, t2.fproduct
from Table1 t1 full join
Table2 t2
on t1.ID = t2.ID
where (t1.ID is null or t2.ID is null) or -- no match as all
(t1.FPRICE <> t2.FPRICE or
t1.FPRODUCT <> t2.FPRODUCT
);
The where clause is a bit more complicated if the column values could be NULL, but your sample data does not have any examples of NULLs.
SELECT *
FROM Table1 t1
FULL JOIN Table2 t2 ON t2.ID = t1.ID
WHERE
t2.TPRICE <> t1.FPRICE
OR t2.TPRODUCT <> t1.FPRODUCT
OR t2.TPRICE IS NULL
OR t1.FPRICE IS NULL
OR t2.TPRODUCT IS NULL
OR t1.FPRODUCT IS NULL
Can you try this query?
SELECT DISTINCT t1.ID t1.FPRICE t1.FPRODUCT
from Table1 t1 LEFT JOIN Table2 ON
Table1.ID = Table2.ID AND Table1.FPRICE = Table2.TPRICE AND Table1.FPRODUCT= Table2.TPRODUCT
WHERE
Table1.ID is NULL or Table1.FPRICE is NULL or Table1.FPRODUCT is NULL
or Table2.TPRICE is NULL or Table2.TPRODUCT is NULL
I would format the answer from Michael1105 as:
SELECT ISNULL(t1.ID,t2.ID),t1.FPRICE,t1.FPRODUCT,t2.TPRICE,t2.TPRODUCT FROM Table_1 t1 FULL JOIN Table_2 t2 ON t2.ID = t1.ID WHERE t2.TPRICE
<>t1.FPRICE OR t2.TPRODUCT
<>t1.FPRODUCT OR t2.TPRICE IS NULL OR t1.FPRICE IS NULL OR t2.TPRODUCT IS NULL OR t1.FPRODUCT IS NULL
for your exact requirement.

Query to count the entries

I have two tables like this.
A B
1 12
2 13
3 12
4 13
5 15
B C
12 APPLE
13 ORANGE
14 MANGO
15 BANANA
I need output as below...
count(A) B C
2 12 APPLE
2 13 ORANGE
0 14 MANGO
1 15 BANANA
I have written the query using joins but I am stuck at displaying the count as zero in case of empty value.
Use a left join to get the values of table2 even if there are no records for them in table1
select T2.B, T2.C, count(T1.A)
from table2 T2
left join table1 T1 on T1.B = T2.B
group by T2.B, T2.C
Try this:
SELECT COUNT(T1.A) as Cnt,T2.B,T2.C
FROM Table2 T2 LEFT JOIN
Table1 T1 ON T1.B=T2.B
GROUP BY T2.B,T2.C
Result:
CNT B C
2 12 APPLE
1 15 BANANA
0 14 MANGO
2 13 ORANGE
See result in SQL Fiddle.
Just to give you another option. You don't need a join, as you only want to show table2 records along with another value which you can get in a sub-query.
select (select count(*) from table1 where table1.B = table2.B) as cnt, B, C
from table2
order by B;
There are other ways to do it (using subquery), but I would use this following one:
-- SETUP
CREATE TABLE #TABLE1 (A INT, B INT);
CREATE TABLE #TABLE2 (B INT, C CHAR(10));
INSERT #TABLE1
SELECT 1, 12 UNION ALL
SELECT 2, 13 UNION ALL
SELECT 3, 12 UNION ALL
SELECT 4, 13 UNION ALL
SELECT 5, 15
INSERT #TABLE2
SELECT 12, 'APPLE' UNION ALL
SELECT 13, 'ORANGE' UNION ALL
SELECT 14, 'MANGO' UNION ALL
SELECT 15, 'BANANA'
-- query
SELECT COUNT(qty.A), dsc.B, dsc.C
FROM #TABLE2 dsc
LEFT JOIN #TABLE1 qty ON (dsc.B = qty.B)
GROUP BY dsc.B, dsc.C
ORDER BY dsc.B, dsc.C;
DECLARE #TABLE1 TABLE (A INT, B INT)
INSERT INTO #TABLE1 VALUES
(1, 12),
(2, 13),
(3, 12),
(4, 13),
(5, 15)
DECLARE #TABLE2 TABLE (B INT, C VARCHAR(20))
INSERT INTO #TABLE2 VALUES
(12,'APPLE'),
(13,'ORANGE'),
(14,'MANGO'),
(15,'BANANA')
SELECT t2.C
,ISNULL(COUNT(t1.B), 0) total_Count
FROM #TABLE2 t2 LEFT JOIN #TABLE1 t1
ON t2.B = t1.B
GROUP BY t2.C
C total_Count
APPLE 2
BANANA 1
MANGO 0
ORANGE 2