I have two tables which has same column names.
For example:
NEEDTOSYNCREQUESTS table
Column Name Value
----------------------------
ID 1
LoadId L1
ShipmentId 123
OrderId NULL
PackageId P456
CustomerOTP 99999
ClientOTP 88888
LASTSYNCEDREQUEST table:
Column Name Value
-------------------------
ID 1
LoadId L1
ShipmentId NULL
OrderId 1234567
PackageId P456
CustomerOTP 44444
ClientOTP 686868
If you compare the above table's column valuesy You could see the following:
CustomerOTP & ClientOTP columns values are not identical.
ShipmentId Column in NEEDTOSYNCREQUESTS has value and ShipmentId Column in LASTSYNCEDREQUEST Table is NULL.
OrderId Column in LASTSYNCEDREQUEST Table has value and ShipmentId Column in NEEDTOSYNCREQUESTS Table is NULL.
So, I need to get the following output. How to achieve this?
OUTPUT
Column Name Value
---------------------------------
ID 1
LoadId NULL
ShipmentId 123
OrderId NULL
PackageId NULL
CustomerOTP 99999
ClientOTP 88888
The condition is, I need to compare the above two tables and needed only the updated column values NEEDTOSYNCREQUESTS Table when compared with another LASTSYNCEDREQUEST Table. Note: Both the columns have same values or NEEDTOSYNCREQUESTS Table Column does not have values then those columns should be null in the Output. PackageId in both the Table is Identical(same). So, I need PackageId to be NULL in the output.
Please help me to achieve this in a SQL query.
Thanks in advance!
As you can see, the same rules implemented in 3 WHENs in a CASE statement for all fields.
SELECT A.ID,
CASE WHEN A.LOADID = B.LOADID THEN NULL
WHEN A.LOADID IS NULL THEN NULL
WHEN (B.LOADID IS NULL AND A.LOADID IS NOT NULL) OR (A.LOADID IS NOT NULL AND B.LOADID IS NOT NULL) THEN A.LOADID END AS LOADID,
CASE WHEN A.SHIPMENTID = B.SHIPMENTID THEN NULL
WHEN A.SHIPMENTID IS NULL THEN NULL
WHEN (B.SHIPMENTID IS NULL AND A.SHIPMENTID IS NOT NULL) OR (A.SHIPMENTID IS NOT NULL AND B.SHIPMENTID IS NOT NULL) THEN A.SHIPMENTID END AS SHIPMENTID,
CASE WHEN A.ORDERID = B.ORDERID THEN NULL
WHEN A.ORDERID IS NULL THEN NULL
WHEN (B.ORDERID IS NULL AND A.ORDERID IS NOT NULL) OR (A.ORDERID IS NOT NULL AND B.ORDERID IS NOT NULL) THEN A.ORDERID END AS ORDERID,
CASE WHEN A.PACKAGEID = B.PACKAGEID THEN NULL
WHEN A.PACKAGEID IS NULL THEN NULL
WHEN (B.PACKAGEID IS NULL AND A.PACKAGEID IS NOT NULL) OR (A.PACKAGEID IS NOT NULL AND B.PACKAGEID IS NOT NULL) THEN A.PACKAGEID END AS PACKAGEID,
CASE WHEN A.CUSTOMEROTP = B.CUSTOMEROTP THEN NULL
WHEN A.CUSTOMEROTP IS NULL THEN NULL
WHEN (B.CUSTOMEROTP IS NULL AND A.CUSTOMEROTP IS NOT NULL) OR (A.CUSTOMEROTP IS NOT NULL AND B.CUSTOMEROTP IS NOT NULL) THEN A.CUSTOMEROTP END AS CUSTOMEROTP,
CASE WHEN A.CLIENTOTP = B.CLIENTOTP THEN NULL
WHEN A.CLIENTOTP IS NULL THEN NULL
WHEN (B.CLIENTOTP IS NULL AND A.CLIENTOTP IS NOT NULL) OR (A.CLIENTOTP IS NOT NULL AND B.CLIENTOTP IS NOT NULL) THEN A.CLIENTOTP END AS CLIENTOTP
FROM
NEEDTOSYNCREQUESTS A
INNER JOIN
LASTSYNCEDREQUEST B
ON A.ID = B.ID;
you can try a case based query like below
See live demo
select
id = N.id,
Loadid = case
when ISNULL(N.Loadid,'')=ISNULL(L.Loadid,'')
then NULL
else N.LoadId
end,
Shipmentid=case
when ISNULL(N.Shipmentid,'')=ISNULL(L.Shipmentid,'')
then NULL
else N.Shipmentid
end,
orderid=case
when ISNULL(N.orderid,'')=ISNULL(L.orderid,'')
then NULL
else N.orderid
end,
packageid=case
when ISNULL(N.packageid,'')=ISNULL(L.packageid,'')
then NULL
else N.packageid
end,
customerOTP=case
when ISNULL(N.customerOTP,'')=ISNULL(L.customerOTP,'')
then NULL
else N.customerOTP
end,
clientOTP=case
when ISNULL(N.clientOTP,'')=ISNULL(L.clientOTP,'')
then NULL
else N.clientOTP
end
from
NEEDTOSYNCREQUESTS N LEFT JOIN
LASTSYNCEDREQUEST L ON
N.id=L.id
Try this:
SELECT n.ID, n.LoadId, n.ShipmentId,
n.OrderId, NULL PackageId, n.CustomerOTP,
n.ClientOTP
FROM NEEDTOSYNCREQUESTS AS n
INNER JOIN LASTSYNCEDREQUEST AS l ON n.ID = l.ID AND n.LoadId = l.LoadId
WHERE n.CustomerOTP <> l.CustomerOTP AND
n.ClientOTP <> l.ClientOTP
AND n.ShipmentId IS NOT NULL
AND l.ShipmentId IS NULL
AND l.OrderId IS NOT NULL
AND l.ShipmentId IS NULL;
SQL Fiddle Demo
| ID | LoadId | ShipmentId | OrderId | PackageId | CustomerOTP | ClientOTP |
|----|--------|------------|---------|-----------|-------------|-----------|
| 1 | L1 | 123 | (null) | (null) | 99999 | 88888 |
Note that, I don't understand why the PackageId should be null, because according to your criteria, it shouldn't. Anyway, I select it as a fixed NULL value, so that you will always get a NULL value no matter what is the actual value.
I often have to solve some case like this when creating data extraction or integration.
So the answer for me will be close to this :
you can use the MERGE function and add some switch case if you want to custom it for some column
MERGE LASTSYNCEDREQUEST TGT
USING (
SELECT
ID,
LoadId,
ShipmentId,
OrderId,
PackageId,
CustomerOTP,
ClientOTP
FROM NEEDTOSYNCREQUESTS
) AS SRC
ON (
SRC.ID = TGT.ID)
WHEN MATCHED
THEN
UPDATE
SET
TGT.ID = SRC.ID
,TGT.LoadID = NULL
,TGT.ShipmentID = SRC.ShipmentID
,TGT.OrderID = NULL
,TGT.PackageID = NULL
,TGT.CustomerOTP = SRC.CustomerOTP
,TGT.ClientOTP = SRC.ClientOTP
WHEN NOT MATCHED
THEN
INSERT (
ID,
LoadId,
ShipmentId,
OrderId,
PackageId,
CustomerOTP,
ClientOTP
)
VALUES (
SRC.ID,
NULL,
SRC.ShipmentId,
NULL,
NULL,
SRC.CustomerOTP,
SRC.ClientOTP
);
SELECT * FROM LASTSYNCEDREQUEST
you can try the code that I write above.
Related
I am trying to find the available address details from three tables.
When table 1 has the address details then get it from table1
If table 1 address has null value then consider table2,
If table 2 address has null value then consider table3, else display table1 address (null)
There are foreign keys in table 1 which can be used to join table 2 and 3 but they can be null as well in which case only data from table 1 to be considered.
In my query, I am able to join the tables when the foreign keys are available but in case they are null, the query doesn’t work!
I am not sure if I can add a ‘Case’ statement to ignore the ‘Join’ conditions in case the foreign keys are null.
Can someone please assist?
My Query is below :
SELECT donor.donor_num,
CASE
--WHEN donor.addr1 IS NULL THEN paraddress.addr1
--WHEN paraddress.addr1 IS NULL THEN enrparaddr.addr1
WHEN donor.addr1 IS NULL THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE
--WHEN donor.addr2 IS NULL THEN paraddress.addr2
--WHEN paraddress.addr2 IS NULL THEN enrparaddr.addr2
WHEN donor.addr2 IS NULL THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
--JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'
Please see attached image for the three tables
You can try below - using FULL OUTER JOIN & coalesce() function
SELECT donor.donor_num,
coalesce(donor.addr1,paraddress.addr1,enrparaddr.addr1) AS Address1,
coalesce(donor.addr2,paraddress.addr2,enrparaddr.addr2) AS Address2
FROM donor
FULL OUTER JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
FULL OUTER JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'
SELECT donor.donor_num,CASE WHEN donor.addr1 IS NULL
THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE WHEN donor.addr2 IS NULL
THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
left join enrparaddr ON enrparaddr.par_code = donor.enrol_code
WHERE donor_num = '17206'
I would recommend:
SELECT d.donor_num,
coalesce(d.addr1, pp.addr1, epe.addr1) AS Address1,
coalesce(d.addr2, pp.addr2, epe.addr2) AS Address2
FROM donor d LEFT JOIN
paraddress pp
ON pp.par_code = d.par_code LEFT JOIN
enrparaddr epe
ON epe.par_code = d.enrol_code AND
pp.par_code IS NULL
WHERE d.donor_num = 17206 -- do not use single quotes for numbers
Notes:
You want a LEFT JOIN because you want all rows in donors.
You should be joining the tables in the order used for the COALESCE().
The second JOIN condition can be limited to cases where the first does not match.
Number constants should not use single quotes.
You can do this with simple Case .. When Statement:
Select Case
When A.ID is NULL And B.ID is NULL And C.ID is NULL Then -- when all columns contain null
NULL
When A.ID is NULL And B.ID is NULL Then
C.ID
When B.ID is NULL and C.ID is NULL Then
A.ID
When A.ID is NULL And C.ID is NULL Then
B.ID
End As ID
From A, B, C
I want to list out notices which are not sent. So I tried the query like below. But its showing wrong result. Is there any way to show notices which are not sent using the following query.
SELECT
vtn.*,
vn.id as notice_id,
vn.vnotice_datetime as sent_notice_time
FROM
vtemplates vt
LEFT JOIN vtemplate_notices vtn ON( vtn.vtemplate_id = vt.id)
LEFT JOIN vnotices vn ON(vn.vtemplate_notice_id = vtn.id AND vn.vnotice_datetime IS nULL)
LEFT JOIN violations v ON ( v.vtemplate_id = vt.id)
WHERE
v.id = 1
Records in a violation_notices table are as follows:
--------------------------------------------------------------
id vtemplate_notice_id desc vnotice_datetime created_on
---------------------------------------------------------------
1 1 test1 22/12/2018 05:30 22/12/2018
Expected Result:
id vtemplate_id created_on notice_id sent_notice_time
---------------------------------------------------------------
2 1 23/12/2018 NULL NULL
3 1 24/12/2018 NULL NULL
4 1 24/12/2018 NULL NULL
Actual Result:
id vtemplate_id created_on notice_id sent_notice_time
---------------------------------------------------------------
1 1 22/12/2018 NULL NULL
2 1 23/12/2018 NULL NULL
3 1 24/12/2018 NULL NULL
4 1 24/12/2018 NULL NULL
In actual result, it shows first record (which should not come) for which vnotice_datetime is NOT NULL but still it's showing.
Well, left joins don't remove non matching rows. Shifting the IS NULL check from the ON to the WHERE clause might work.
SELECT vtn.*,
vn.id notice_id,
vn.vnotice_datetime sent_notice_time
FROM vtemplates vt
LEFT JOIN vtemplate_notices vtn
ON vtn.vtemplate_id = vt.id
LEFT JOIN vnotices vn
ON vn.vtemplate_notice_id = vtn.id
LEFT JOIN violations v
ON v.vtemplate_id = vt.id
WHERE v.id = 1
AND vn.vnotice_datetime IS NULL;
You can use NOT EXISTS or test the joined column IS NULL in the WHERE clause
https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
e.g
SELECT * FROM violations
WHERE NOT EXISTS(
SELECT * FROM notifications
WHERE violation_id = violations.id
)
SELECT v.*, n.* FROM violations v
LEFT JOIN notifications n
ON n.violation_id = v.id
WHERE n.violation_id IS NULL
I have a query given below
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] != null THEN Ap.Name ELSE B.[Name]END Name,
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id
In the Case When query I am trying to return the Name based on the b.ApId value.
But even if b.ApId is not null I am getting B.Name instead of Ap.Name.
Can anyone point out where I am going wrong.
!= will evaluate for values, while NULL is not a value.
So you have to either use IS NULL or IS NOT NULL to compare nulls.
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] is not null THEN Ap.Name ELSE B.[Name]END Name,
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id
Use IS NOT NULL, IS NULL to compare with NULL value, Or use ISNULL, COALESCE function
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] IS NOT NULL THEN Ap.Name ELSE B.[Name] END Name
-- ISNULL(Ap.Name, B.[Name]) as Name
-- COALESCE(Ap.Name, B.[Name],'') as Name
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id
I have a table as following.
id | firstname| lastname | email | homephone
-------------------------------------------------------
1 | aaa | bbb | xxx#yyy.com | 12344444
2 | aaa | bbb | null | null
3 | ccc | ddd | zzz#fff.com | null
4 | ccc | ddd | null | 34343322
The issue is I want to keep only 1 record since these are considered as duplicates and merge the nulls so that the table appears as follows
1 aaa | bbb | xxx#yyy.com | 12344444
3 ccc | ddd | zzz#fff.com | 3433322
So far I have managed to get the duplicates using the following the code
Select
max(a.id) as original id, b.id as DuplicateId,
a.firstname, b.firstname as dup_fname,
a.lastname, b.lastname as dup_lname,
a.email, b.email
From
tbl_xxx a
join
tbl_xxx b on a.firstname = b.firstname
and a.lastname = b.lastname
and a.email is null
and a.homephone is null
and b.email is null
and b.homephone is null
and v.id < v2.id
Group by
b.id, a.firstname, b.firstname, a.lastname,
b.lastname, a.homephone, b.homephone
My merge query looks like this
update tbl_xxx
SET
email = email ,
phone = phone
where
firstname = firstname
and lastname = lastname
and email is null
and phone is null
Eventually I will get distinct rows.
Is my approach correct? kindly suggest how can I make my query more efficient
update tbl_tmpdupes3 SET
email = email ,
phone = phone ,
where
firstname=firstname
and lastname=lastname
and email is null
and homephone is null
will do absolutely nothing, since the query is not comparing the table against itself, but each row against itself. Using an update won't work either, you'll still have duplicates. What you want is to remove the duplicate data entirely, AFTER doing an update comparing the table to itself. So, basically we run one query that ensures all information in duplicates that is not null is copied to the originals, then we delete the higher value pk.
One way of tackling the problem update one column at a time:
update tbl_xxx SET tbl_xxx.email = tmp.email
FROM (SELECT tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.email FROM tbl_xxx
WHERE NOT tbl_xxx.email IS NULL LIMIT 1)
AS tmp ON tmp.firstname = tbl_xxx.firstname AND tmp.lastname = tbl_xxx.lastname
WHERE tbl_xxx.email IS NULL;
update tbl_xxx SET tbl_xxx.phone = tmp.phone
FROM (SELECT tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone FROM tbl_xxx
WHERE NOT tbl_xxx.phone IS NULL LIMIT 1)
AS tmp ON tmp.firstname = tbl_xxx.firstname AND tmp.lastname = tbl_xxx.lastname
WHERE tbl_xxx.phone is NULL;
The query finds the values of each column for first name and last name, and copies over first value it finds into null fields. So, if the original data was missing, it will add it. It may not be 100% correct if two different people in the DB have the same name, you'll have to take that into consideration.
That said, follow it up with this query, which should only delete the higher-pk row that is identical.
DELETE FROM tbl_xxx WHERE tbl_xxx.id IN (
SELECT max(id) FROM tbl_xxx
GROUP BY tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone,tbl_xxx.email
HAVING count(tbl_xxx.id) > 1));
Edit: if there are potentially multiple duplicates, you could do:
DELETE FROM tbl_xxx WHERE tbl_xxx.id NOT IN (
SELECT min(id) FROM tbl_xxx
GROUP BY tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone,tbl_xxx.email);
you can use Merge statement for this. Try this sample.
create table temptable (id int, firstname varchar(50), lastname varchar(50), email varchar(50), homephone varchar(50))
insert into temptable values
(1,'aaa' , 'bbb', 'xxx#yyy.com', 1234444),
(2,'aaa' , 'bbb', null, null),
(3,'ccc' , 'ddd', 'abc#ddey.com', null),
(4,'ccc' , 'ddd', null, 34343322 )
select * from temptable
;with cte as
(
select firstname, lastname
,(select top 1 id from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and ( b.email is not null or b.homephone is not null)) tid
,(select top 1 email from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and b.email is not null ) email
,(select top 1 homephone from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and b.homephone is not null ) homephone
from temptable a
group by firstname , lastname
)
--select * from cte
merge temptable as a
using cte as b
on ( a.id = b.tid )
when matched
then
update set a.email = b.email , a.homephone = b.homephone
when not matched by source then
delete ;
select * from temptable
drop table temptable
Here is the situation that I'm facing:
I have two tables A and B. If records are in table A and not in table B they need to be added to table B. If records are in table B and not in table A, then they need to be removed out of table B. The trick here is that it is the mixture of two keys that makes the unique combination
Table A
Operation_Key Part_Key
1 1
1 2
2 1
2 3
Table B
Operation_Key Part_Key Record_Key
1 1 1
2 1 2
2 3 3
2 4 4
I am trying to get the right type of query so that the results returned look like
Results
Operation_Key Part_Key Record_Key Action
1 2 NULL Add
2 4 4 Delete
The query I have so far looks like similar to this:
CREATE TABLE #Action_Table
(
Action VARCHAR(6),
Action_Bit INT,
Operation_Key INT,
Record_Key INT,
Part_Key INT
)
INSERT INTO #Action_Table
SELECT
CASE
WHEN WS.Operation_Key IS NULL THEN 'Delete'
WHEN WS.Operation_Key IS NOT NULL THEN 'Add'
END Action,
CASE
WHEN WS.Operation_Key IS NULL THEN '0'
WHEN WS.Operation_Key IS NOT NULL THEN '1'
END Action_Bit,
CASE
WHEN WS.Operation_Key IS NULL THEN WC.Operation_Key
WHEN WS.Operation_Key IS NOT NULL THEN WS.Operation_Key
END Operation_Key,
CASE
WHEN WS.Operation_Key IS NULL THEN WC.Record_Key
WHEN WS.Operation_Key IS NOT NULL THEN NULL
END Workcenter_Component_Key,
CASE
WHEN WS.Operation_Key IS NULL THEN WC.Part_Key
WHEN WS.Operation_Key IS NOT NULL THEN WS.Part_Key
END Part_Key
FROM #WS_Part_Table WS
FULL OUTER JOIN #WC_Part_Table WC
ON WC.Part_Key = WS.Part_Key
AND WC.Operation_Key = WS.Operation_Key
WHERE (WS.Part_Key IS NULL or WC.Part_Key IS NULL) AND (WS.Operation_Key IS NULL or WC.Operation_Key IS NULL)
Both the #WS_Part_Table and the #WC_Part_Table are temp tables that I'm constructing using queries, but my dilemma is that I have to PRE-QUERY the #WC_Part_Table query on the operation key that I'm interested in, otherwise I get way too many results.
This is the query that I'm using to create the #WC_Part_Table
CREATE TABLE #WC_Part_Table
(
Operation_Key INT,
Record_Key INT,
Part_Key INT
)
-- Workcenter Component Table
INSERT INTO #WC_Part_Table
SELECT
O.Operation_Key,
WC.Record_Key,
WC.Part_Key
FROM Workcenter_Component WC
JOIN Operation O
ON O.Default_Workcenter_Key = WC.Workcenter_Key
/* There is some reason why this next line is needed */
WHERE O.Operation_Key = 23149
Tyr this to get the results that you have posted:
SELECT COALESCE(a.Operation_Key, b.Operation_Key) Operation_Key,
COALESCE(a.Part_Key, b.Part_Key) Part_Key,
Record_Key,
CASE
WHEN Record_Key IS NULL THEN 'Add'
ELSE 'Delete'
END Action
FROM TableA a FULL OUTER JOIN TableB b
ON a.Operation_Key = b.Operation_Key
AND a.Part_Key = b.Part_Key
WHERE (a.Operation_Key IS NULL) OR (b.Operation_Key IS NULL)
Test Script:
CREATE TABLE #TableA
(
Operation_Key INT,
Part_Key INT
)
INSERT INTO #TableA
SELECT 1,1
UNION
SELECT 1,2
UNION
SELECT 2,1
UNION
SELECT 2,3
CREATE TABLE #TableB
(
Operation_Key INT,
Part_Key INT,
Record_Key INT
)
INSERT INTO #TableB
SELECT 1,1,1
UNION
SELECT 2,1,2
UNION
SELECT 2,3,3
UNION
SELECT 2,4,4
SELECT COALESCE(a.Operation_Key, b.Operation_Key) Operation_Key,
COALESCE(a.Part_Key, b.Part_Key) Part_Key,
Record_Key,
CASE
WHEN Record_Key IS NULL THEN 'Add'
ELSE 'Delete'
END Action
FROM #TableA a FULL OUTER JOIN #TableB b
ON a.Operation_Key = b.Operation_Key
AND a.Part_Key = b.Part_Key
WHERE (a.Operation_Key IS NULL) OR (b.Operation_Key IS NULL)
Output:
Operation_Key Part_Key Record_Key Action
1 2 NULL Add
2 4 4 Delete
Add to B:
insert into B (Operation_Key, Part_Key, Record_Key)
values
select Operation_Key, Part_Key, null as Record_Key from A
left join b on a.Operation_Key = b.Operation_Key and
a.Part_Key = b.Part_Key
where b.Part_Key is null
Delete from B:
Delete from B
select * from B left join A on b.Operation_Key = a.Operation_Key and
b.Part_Key = a.Part_Key
where a.Operation_Key is null
You can get exactly the results table you want (looking at your example set up) by making clever use of the SQL "COALESCE" operator. If you use a query like this:
SELECT
COALESCE(A.Operation_Key, B.Operation_Key) as Operation_Key,
COALESCE(A.part_key, B.part_key) as Part_Key,
B.Record_Key,
CASE WHEN A.Operation_Key IS NULL THEN
'Delete'
ELSE
'Add'
END AS [Action] FROM A
FULL OUTER JOIN B
ON A.Operation_Key = B.Operation_Key
AND A.Part_Key= B.Part_Key
WHERE A.Operation_Key IS NULL
OR B.Operation_Key IS NULL
...you'll get a result table exactly like your example.