Check col1 if duplicate then check col2 if distinct - sql

Hey guys I've been struggling to get a simple query done in SnowFlake.
A sample of the data is explained below,
Number
ID
2559
23
2559
33
2559
55
2550
89
2499
14
2499
14
Based on the table above I would like to create a column that checks if (column Number) have duplicated values if yes; then check (column ID) if the values associated with that Number were duplicated or distinct. If values were duplicated then return 0 if values were distinct then return 1.
The desired outcome is as follows,
Number
ID
Check
2559
23
1
2559
33
1
2559
55
1
2550
89
0
2499
14
0
2499
14
0
and the last outcome should be on the Number column level (group by) and would be like the following table,
Number
Check
2559
1
2550
0
2499
0
Any suggestions are appreciated.
Edited tables
The scenario has changed based on new requirements
The original table have two IDs (ID1 and ID2) and those IDs must be linked to two different tables T-ID1 and T-ID2.
Number
ID1
ID2
2559
23
null
2559
33
null
2559
55
null
2550
89
null
2499
14
null
2499
14
null
2498
null
14
2498
null
50
2498
null
null
So the idea is if Number has duplicated IDs (in ID1 or ID2) then return 1, if Number has unique ID (in ID1 or ID2) then return ID1 or ID2. if Number have null values for ID1 and ID2 then ignore the entire row.
This is the query I am using - everything works based on solution provided below, but I am getting nulls along with ID values.
ID1 is linked to Supplier_ID_Ekuep and ID2 is linked to Supplier_ID_Qava.
select wbd.WAYBILL_ID, sup.WAYBILL_NO,
sup.Supplier_ID_Qava, supq.Supplier_Qava, supq.Supllier_City_Qava, supq.Supplier_Qava_Add,
sup.Supplier_ID_Ekuep, supc.Supplier_Ekuep, supc.Supllier_City_Ekuep, supc.Supplier_Ekuep_Add
from WAYBILL_PRODUCTS wbd
left join (select wb.WAYBILL_ID, ow.WAYBILL_NO,
case when mult.multi_supp_qava = 1 then '1'
when mult.multi_supp_qava = 0 then op.ID_Supplier_Qava
else null end as Supplier_ID_Qava,
case when mult.multi_supp_ekuep = 1 then '1'
when mult.multi_supp_ekuep = 0 then op.ID_Supplier_Ekuep
else null end as Supplier_ID_Ekuep
from WAYBILL_PRODUCTS wb
left join (select ID, ORDER_ID, WAYBILL_NO from ORDER_WAYBILLS) ow on wb.WAYBILL_ID = ow.id
left join (select opr.ID_ORDER, opr.ID_PRODUCT, ss.ID_Supplier_Ekuep, ss.ID_Supplier_Qava
from ORDER_PRODUCTS opr
left join (select s.id, supc.*, supq.*
from SUPPLIERS s
left join (select ID_SUPPLIER as ID_Supplier_Ekuep
from EKUEP_KSA_EKUEP_STAGING.PS_SUPPLIER where USED_SUPPLIER_ID is null) supc on supc.ID_Supplier_Ekuep = s.ID_SUPPLIER and s.STORE_ID = 1
left join (select ID_SUPPLIER as ID_Supplier_Qava
from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_SUPPLIER where USED_SUPPLIER_ID is null) supq on supq.ID_Supplier_Qava = s.ID_SUPPLIER and s.STORE_ID = 2) ss on opr.SUPPLIER_ID = ss.ID
group by opr.ID_ORDER, opr.ID_PRODUCT, ss.ID_Supplier_Ekuep, ss.ID_Supplier_Qava) op on op.ID_PRODUCT = wb.PRODUCT_ID and op.ID_ORDER = ow.ORDER_ID
------------------------------------------------------------------------------------------------------------------------
left join (select wb.WAYBILL_ID, ow.WAYBILL_NO,
(count(distinct op.ID_Supplier_Qava) > 1)::int as multi_supp_qava,
(count(distinct op.ID_Supplier_Ekuep) > 1)::int as multi_supp_ekuep
from WAYBILL_PRODUCTS wb
left join (select ID, ORDER_ID, WAYBILL_NO from ORDER_WAYBILLS) ow on wb.WAYBILL_ID = ow.id
left join (select opr.ID_ORDER, opr.ID_PRODUCT, ss.ID_Supplier_Ekuep, ss.ID_Supplier_Qava
from ORDER_PRODUCTS opr
left join (select s.id, supc.ID_Supplier_Ekuep, supq.ID_Supplier_Qava
from SUPPLIERS s
left join (select ID_SUPPLIER as ID_Supplier_Ekuep
from EKUEP_KSA_EKUEP_STAGING.PS_SUPPLIER where USED_SUPPLIER_ID is null) supc on supc.ID_Supplier_Ekuep = s.ID_SUPPLIER and s.STORE_ID = 1
left join (select ID_SUPPLIER as ID_Supplier_Qava
from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_SUPPLIER where USED_SUPPLIER_ID is null) supq on supq.ID_Supplier_Qava = s.ID_SUPPLIER and s.STORE_ID = 2
) ss on opr.SUPPLIER_ID = ss.ID
group by opr.ID_ORDER, opr.ID_PRODUCT, ss.ID_Supplier_Ekuep, ss.ID_Supplier_Qava) op on op.ID_PRODUCT = wb.PRODUCT_ID and op.ID_ORDER = ow.ORDER_ID
where _FIVETRAN_DELETED = 0
group by wb.WAYBILL_ID, ow.WAYBILL_NO) mult on mult.WAYBILL_NO = ow.WAYBILL_NO
------------------------------------------------------------------------------------------------------------------------
group by wb.WAYBILL_ID, ow.WAYBILL_NO, mult.multi_supp_qava, mult.multi_supp_ekuep, op.ID_Supplier_Qava, op.ID_Supplier_Ekuep) sup on wbd.WAYBILL_ID = sup.WAYBILL_ID
left join
(select ps.ID_SUPPLIER as ID_Supplier_Qava,
ps.name as Supplier_Qava,
listagg(distinct pa.CITY, ', ') as Supllier_City_Qava,
ps.DATE_ADD as Supplier_Qava_Add
from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_SUPPLIER ps
left join (select * from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_ADDRESS) pa on pa.ID_SUPPLIER = ps.ID_SUPPLIER and pa._FIVETRAN_DELETED = 0
where ps.USED_SUPPLIER_ID is null and ps._FIVETRAN_DELETED = 0
group by ID_Supplier_Qava, Supplier_Qava, Supplier_Qava_Add) supq on supq.ID_Supplier_Qava = sup.Supplier_ID_Qava
left join
(select ps.ID_SUPPLIER as ID_Supplier_Ekuep,
ps.name as Supplier_Ekuep,
listagg(distinct pa.CITY, ', ') as Supllier_City_Ekuep,
ps.DATE_ADD as Supplier_Ekuep_Add
from EKUEP_KSA_EKUEP_STAGING.PS_SUPPLIER ps
left join (select * from EKUEP_KSA_EKUEP_STAGING.PS_ADDRESS) pa on pa.ID_SUPPLIER = ps.ID_SUPPLIER and pa._FIVETRAN_DELETED = 0
where ps.USED_SUPPLIER_ID is null and ps._FIVETRAN_DELETED = 0
group by ID_Supplier_Ekuep, Supplier_Ekuep, Supplier_Ekuep_Add) supc on supc.ID_Supplier_Ekuep = sup.Supplier_ID_Ekuep
where _FIVETRAN_DELETED = 0
group by wbd.WAYBILL_ID, sup.WAYBILL_NO,
sup.Supplier_ID_Qava, supq.Supplier_Qava, supq.Supllier_City_Qava, supq.Supplier_Qava_Add,
sup.Supplier_ID_Ekuep, supc.Supplier_Ekuep, supc.Supllier_City_Ekuep, supc.Supplier_Ekuep_Add
The output I am getting for Waybill_No = 43265104 is as follows, I just want to get rid of the null row.

WITH data(num, id) AS (
SELECT * FROM VALUES
(2559, 23),
(2559, 33),
(2559, 55),
(2550, 89),
(2499, 14),
(2499, 14)
)
SELECT
num,
id,
count(*) over(partition by num) as num_dup,
count(distinct id)over(partition by num) as id_dup,
iff(num_dup > 1 AND num_dup = id_dup, 1, 0) as "check"
FROM data;
gives:
NUM
ID
NUM_DUP
ID_DUP
check
2559
23
3
3
1
2559
33
3
3
1
2559
55
3
3
1
2550
89
1
1
0
2499
14
2
1
0
2499
14
2
1
0
Extra Data:
WITH data(num, id) AS (
SELECT * FROM VALUES
(2559, 23),
(2559, 33),
(2559, 33),
(2559, 55),
(2550, 89),
(2499, 14),
(2499, 14)
)
SELECT
num,
id,
count(*) over(partition by num) as num_dup,
count(distinct id)over(partition by num) as id_dup,
iff(num_dup > 1 AND num_dup = id_dup, 1, 0) as "check"
FROM data;
if we make 2559 have two 33's then it show change to 0/false
NUM
ID
NUM_DUP
ID_DUP
check
2559
23
4
3
0
2559
33
4
3
0
2559
33
4
3
0
2559
55
4
3
0
2550
89
1
1
0
2499
14
2
1
0
2499
14
2
1
0
Last Step:
WITH data(num, id) AS (
SELECT * FROM VALUES
(2559, 23),
(2559, 33),
(2559, 55),
(2550, 89),
(2499, 14),
(2499, 14)
)
SELECT
num,
iff(count(*) > 1 AND count(*) = count(distinct id), 1, 0) as output
FROM data
GROUP BY 1;
gives:
NUM
OUTPUT
2559
1
2550
0
2499
0

left join (
select
ID,
ORDER_ID,
WAYBILL_NO
from ORDER_WAYBILLS
) ow
on wb.WAYBILL_ID = ow.id
should just be:
LEFT JOIN order_waybills AS ow
ON wb.waybill_id = ow.id
Gaint Refactoing Starts Here
So I start refactoring this SQL, the first part was to ignore my prior "this could be simpler" and move that into a CTE ob_cte, so it was "just simple" then I notice the first two sections had large block you noted as op that where the same, so that becomes a CTE op_cte also then that gives us:
WITH ob_cte AS (
SELECT
id,
order_id,
waybill_no
FROM order_waybills
), op_etc AS (
SELECT
opr.id_order,
opr.id_product,
ss.id_supplier_ekuep,
ss.id_supplier_qava
FROM order_products AS opr
LEFT JOIN (
SELECT
s.id,
supc.id_supplier_ekuep,
supq.id_supplier_qava
FROM suppliers AS s
LEFT JOIN (
SELECT
id_supplier AS id_supplier_ekuep
FROM ekuep_ksa_ekuep_staging.ps_supplier
WHERE used_supplier_id IS NULL
) AS supc
ON supc.id_supplier_ekuep = s.id_supplier
AND s.store_id = 1
LEFT JOIN (
SELECT
id_supplier AS id_supplier_qava
FROM qavashop_ksa_qavaish_mainshop.ps_supplier
WHERE used_supplier_id IS NULL
) AS supq
ON supq.id_supplier_qava = s.id_supplier
AND s.store_id = 2
) AS ss
ON opr.SUPPLIER_ID = ss.ID
GROUP BY opr.id_order, opr.id_product, ss.id_supplier_ekuep, ss.id_supplier_qava
)
SELECT
wbd.waybill_id,
sup.waybill_no,
sup.supplier_id_qava,
supq.supplier_qava,
supq.supllier_city_qava,
supq.supplier_qava_add,
sup.supplier_id_ekuep,
supc.supplier_ekuep,
supc.supllier_city_ekuep,
supc.supplier_ekuep_add
FROM waybill_products AS wbd
LEFT JOIN (
SELECT
wb.waybill_id,
ow.waybill_no,
CASE
WHEN mult.multi_supp_qava = 1 THEN '1'
WHEN mult.multi_supp_qava = 0 THEN op.ID_Supplier_Qava
ELSE NULL
end as supplier_id_qava,
case
WHEN mult.multi_supp_ekuep = 1 THEN '1'
WHEN mult.multi_supp_ekuep = 0 THEN op.ID_Supplier_Ekuep
ELSE NULL
END AS supplier_id_ekuep
FROM waybill_products AS wb
LEFT JOIN ob_cte AS ow
ON wb.waybill_id = ow.id
LEFT JOIN op_etc AS op
ON op.id_product = wb.product_id
AND op.id_order = ow.order_id
------------------------------------------------------------------------------------------------------------------------
left join (
select
wb.WAYBILL_ID,
ow.WAYBILL_NO,
(count(distinct op.ID_Supplier_Qava) > 1)::int as multi_supp_qava,
(count(distinct op.ID_Supplier_Ekuep) > 1)::int as multi_supp_ekuep
from WAYBILL_PRODUCTS wb
LEFT JOIN ob_cte AS ow
ON wb.waybill_id = ow.id
left join op_etc AS op
on op.ID_PRODUCT = wb.PRODUCT_ID
and op.ID_ORDER = ow.ORDER_ID
where _FIVETRAN_DELETED = 0
group by wb.WAYBILL_ID, ow.WAYBILL_NO
) AS mult
on mult.WAYBILL_NO = ow.WAYBILL_NO
------------------------------------------------------------------------------------------------------------------------
group by wb.WAYBILL_ID, ow.WAYBILL_NO, mult.multi_supp_qava, mult.multi_supp_ekuep, op.ID_Supplier_Qava, op.ID_Supplier_Ekuep
) AS sup
on wbd.WAYBILL_ID = sup.WAYBILL_ID
left join (
select
ps.id_supplier AS id_supplier_qava,
ps.name AS supplier_qava,
ps.date_add AS supplier_qava_add,
LISTAGG(DISTINCT pa.CITY, ', ') AS supllier_city_qava
from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_SUPPLIER ps
left join (
select *
from QAVASHOP_KSA_QAVAISH_MAINSHOP.PS_ADDRESS
) pa
ON pa.ID_SUPPLIER = ps.ID_SUPPLIER
AND pa._fivetran_deleted = 0
WHERE ps.USED_SUPPLIER_ID is null
AND ps._fivetran_deleted = 0
GROUP BY 1, 2, 3
) AS supq
on supq.ID_Supplier_Qava = sup.Supplier_ID_Qava
left join (
select
ps.id_supplier AS id_supplier_ekuep,
ps.name AS supplier_ekuep,
ps.date_add AS supplier_ekuep_add,
LISTAGG(DISTINCT pa.CITY, ', ') AS supllier_city_ekuep
FROM ekuep_ksa_ekuep_staging.ps_supplier AS ps
LEFT JOIN FROM ekuep_ksa_ekuep_staging.ps_address AS pa
ON pa.id_supplier = ps.id_supplier
and pa._fivetran_deleted = 0
WHERE ps.used_supplier_id IS NULL
and ps._fivetran_deleted = 0
GROUP BY 1, 2, 4
) AS supc
ON supc.id_supplier_ekuep = sup.supplier_id_ekuep
WHERE _fivetran_deleted = 0
GROUP BY wbd.waybill_id, sup.waybill_no,
sup.supplier_id_qava, supq.supplier_qava,
supq.supllier_city_qava, supq.supplier_qava_add,
sup.supplier_id_ekuep, supc.supplier_ekuep,
supc.supllier_city_ekuep, supc.supplier_ekuep_add;
Now op_etc itself, that GROUP BY at the end is really just a DISTINCT so we can swap that in. Also in ss of that op_cte
SELECT
s.id,
supc.id_supplier_ekuep,
supq.id_supplier_qava
FROM suppliers AS s
LEFT JOIN (
SELECT
id_supplier AS id_supplier_ekuep
FROM ekuep_ksa_ekuep_staging.ps_supplier
WHERE used_supplier_id IS NULL
) AS supc
ON supc.id_supplier_ekuep = s.id_supplier
AND s.store_id = 1
LEFT JOIN (
SELECT
id_supplier AS id_supplier_qava
FROM qavashop_ksa_qavaish_mainshop.ps_supplier
WHERE used_supplier_id IS NULL
) AS supq
ON supq.id_supplier_qava = s.id_supplier
AND s.store_id = 2
those to left joins, keep only values that are NULL and then LEFT JOIN of two requirements which means we are get a row per suppliers the IS NULL can be moved to the ON with no impact, which means the rename can be moved higher up, and the sub-select dropped, so that section can become:
SELECT
s.id,
supc.id_supplier AS id_supplier_ekuep,
supq.id_supplier AS id_supplier_qava
FROM suppliers AS s
LEFT JOIN ekuep_ksa_ekuep_staging.ps_supplier AS supc
ON supc.id_supplier = s.id_supplier
AND s.store_id = 1
AND supc.used_supplier_id IS NULL
LEFT JOIN qavashop_ksa_qavaish_mainshop.ps_supplier AS supq
ON supq.id_supplier = s.id_supplier
AND s.store_id = 2
AND supq.used_supplier_id IS NULL
thus the op_cte becomes:
), op_etc AS (
SELECT DISTINCT
opr.id_order,
opr.id_product,
ss.id_supplier_ekuep,
ss.id_supplier_qava
FROM order_products AS opr
LEFT JOIN (
SELECT
s.id,
supc.id_supplier AS id_supplier_ekuep,
supq.id_supplier AS id_supplier_qava
FROM suppliers AS s
LEFT JOIN ekuep_ksa_ekuep_staging.ps_supplier AS supc
ON supc.id_supplier = s.id_supplier
AND s.store_id = 1
AND supc.used_supplier_id IS NULL
LEFT JOIN qavashop_ksa_qavaish_mainshop.ps_supplier AS supq
ON supq.id_supplier = s.id_supplier
AND s.store_id = 2
AND supq.used_supplier_id IS NULL
) AS ss
ON opr.SUPPLIER_ID = ss.ID
)
which actually means the ss can just be left joined as first order things like:
), op_etc AS (
SELECT DISTINCT
opr.id_order,
opr.id_product,
supc.id_supplier AS id_supplier_ekuep,
supq.id_supplier AS id_supplier_qava
FROM order_products AS opr
LEFT JOIN suppliers AS s
opr.SUPPLIER_ID = s.ID
LEFT JOIN ekuep_ksa_ekuep_staging.ps_supplier AS supc
ON supc.id_supplier = s.id_supplier
AND s.store_id = 1
AND supc.used_supplier_id IS NULL
LEFT JOIN qavashop_ksa_qavaish_mainshop.ps_supplier AS supq
ON supq.id_supplier = s.id_supplier
AND s.store_id = 2
AND supq.used_supplier_id IS NULL
)
ah thats much more refreshing..
in the sub-select sup` I am worried, that you are grouping by values that are not in you output set, so you will get duplicate rows
in this case block
CASE
WHEN mult.multi_supp_qava = 1 THEN '1'
WHEN mult.multi_supp_qava = 0 THEN op.ID_Supplier_Qava
ELSE NULL
end as supplier_id_qava,
you are group not by the output supplier_id_qava or it's position 3 but mult.multi_supp_qava, op.ID_Supplier_Qava
so if op.ID_Supplier_Qava is not null when mult.multi_supp_qava = 1 and can have different values, the supplier_id_qava will output 1 on both rows, but they will not merge, as op.ID_Supplier_Qava is different. This is the root of my strong dislike for using the input to the SELECT section as the grouping clauses of the aggregation of those values. because through transformation, they can become the same on the output, but remain different on the input, and produce hard to debug deuplicates. And if the flip case that they are alway safe/null/constant in the odd case, this is not clear to the SQL reader. (on this point I have to say a strong thank you for have used the aliases on select etc, as that alway confidance of where those values are coming from).
So again the GROUP BY on sup has no agration of values so this is a hidden DISTINCT, but it not giving distinct values perhaps in all cases.
So after moving some sub-selects into CTE's as I find it makes each select layer show, just what it is doing, with have to leap over smaller details we get SQL like this:
WITH ob_cte AS (
SELECT
id,
order_id,
waybill_no
FROM order_waybills
), op_etc AS (
SELECT DISTINCT
opr.id_order,
opr.id_product,
supc.id_supplier AS id_supplier_ekuep,
supq.id_supplier AS id_supplier_qava
FROM order_products AS opr
LEFT JOIN suppliers AS s
opr.SUPPLIER_ID = s.ID
LEFT JOIN ekuep_ksa_ekuep_staging.ps_supplier AS supc
ON supc.id_supplier = s.id_supplier
AND s.store_id = 1
AND supc.used_supplier_id IS NULL
LEFT JOIN qavashop_ksa_qavaish_mainshop.ps_supplier AS supq
ON supq.id_supplier = s.id_supplier
AND s.store_id = 2
AND supq.used_supplier_id IS NULL
), mult_cte AS (
SELECT
wb.waybill_id,
ow.waybill_no,
(COUNT(DISTINCT op.id_supplier_qava) > 1)::int AS multi_supp_qava,
(COUNT(DISTINCT op.id_supplier_ekuep) > 1)::int AS multi_supp_ekuep
FROM waybill_products AS wb
LEFT JOIN ob_cte AS ow
ON wb.waybill_id = ow.id
LEFT JOIN op_etc AS op
ON op.id_product = wb.product_id
AND op.id_order = ow.order_id
WHERE _fivetran_deleted = 0
GROUP BY wb.waybill_id, ow.waybill_no
), supq_cte AS (
SELECT
ps.id_supplier AS id_supplier_qava,
ps.name AS supplier_qava,
ps.date_add AS supplier_qava_add,
LISTAGG(DISTINCT pa.city, ', ') AS supllier_city_qava
FROM qavashop_ksa_qavaish_mainshop.ps_supplier AS ps
LEFT JOIN qavashop_ksa_qavaish_mainshop.ps_address AS pa
ON pa.id_supplier = ps.id_supplier
AND pa._fivetran_deleted = 0
WHERE ps.used_supplier_id is null
AND ps._fivetran_deleted = 0
GROUP BY 1, 2, 3
), supc_cte AS (
SELECT
ps.id_supplier AS id_supplier_ekuep,
ps.name AS supplier_ekuep,
ps.date_add AS supplier_ekuep_add,
LISTAGG(DISTINCT pa.city, ', ') AS supllier_city_ekuep
FROM ekuep_ksa_ekuep_staging.ps_supplier AS ps
LEFT JOIN FROM ekuep_ksa_ekuep_staging.ps_address AS pa
ON pa.id_supplier = ps.id_supplier
AND pa._fivetran_deleted = 0
WHERE ps.used_supplier_id IS NULL
AND ps._fivetran_deleted = 0
GROUP BY 1, 2, 4
), sup_cte AS (
SELECT DISTINCT
wb.waybill_id,
ow.waybill_no,
CASE
WHEN mult.multi_supp_qava = 1 THEN '1'
WHEN mult.multi_supp_qava = 0 THEN op.ID_Supplier_Qava
ELSE NULL
end as supplier_id_qava,
case
WHEN mult.multi_supp_ekuep = 1 THEN '1'
WHEN mult.multi_supp_ekuep = 0 THEN op.ID_Supplier_Ekuep
ELSE NULL
END AS supplier_id_ekuep
FROM waybill_products AS wb
LEFT JOIN ob_cte AS ow
ON wb.waybill_id = ow.id
LEFT JOIN op_etc AS op
ON op.id_product = wb.product_id
AND op.id_order = ow.order_id
------------------------------------------------------------------------------------------------------------------------
LEFT JOIN mult_cte AS mult
on mult.WAYBILL_NO = ow.WAYBILL_NO
------------------------------------------------------------------------------------------------------------------------
)
SELECT
wbd.waybill_id,
sup.waybill_no,
sup.supplier_id_qava,
supq.supplier_qava,
supq.supllier_city_qava,
supq.supplier_qava_add,
sup.supplier_id_ekuep,
supc.supplier_ekuep,
supc.supllier_city_ekuep,
supc.supplier_ekuep_add
FROM waybill_products AS wbd
LEFT JOIN sup_cte AS sup
ON wbd.WAYBILL_ID = sup.WAYBILL_ID
LEFT JOIN supq_cte AS supq
ON supq.id_supplier_qava = sup.supplier_id_qava
LEFT JOIN supc_cte AS supc
ON supc.id_supplier_ekuep = sup.supplier_id_ekuep
WHERE _fivetran_deleted = 0
GROUP BY wbd.waybill_id, sup.waybill_no,
sup.supplier_id_qava, supq.supplier_qava,
supq.supllier_city_qava, supq.supplier_qava_add,
sup.supplier_id_ekuep, supc.supplier_ekuep,
supc.supllier_city_ekuep, supc.supplier_ekuep_add;
And at the end we see again you are suffering from duplicate data, that you are trying to clean away with yet another GROUP BY.. so we will switch to a DISTINCT
SELECT DISTINCT
wbd.waybill_id,
sup.waybill_no,
sup.supplier_id_qava,
supq.supplier_qava,
supq.supllier_city_qava,
supq.supplier_qava_add,
sup.supplier_id_ekuep,
supc.supplier_ekuep,
supc.supllier_city_ekuep,
supc.supplier_ekuep_add
FROM waybill_products AS wbd
LEFT JOIN sup_cte AS sup
ON wbd.WAYBILL_ID = sup.WAYBILL_ID
LEFT JOIN supq_cte AS supq
ON supq.id_supplier_qava = sup.supplier_id_qava
LEFT JOIN supc_cte AS supc
ON supc.id_supplier_ekuep = sup.supplier_id_ekuep
WHERE _fivetran_deleted = 0
Right so what was your question again?
you want to get rid of all the nulls... if this is so "why so many left joins" or returning null from CASE statements..
Right so in the picture to show a waybill_no with values, and another where supplier_id_qava is null, given the later comes from
LEFT JOIN sup_cte AS sup
ON wbd.WAYBILL_ID = sup.WAYBILL_ID
and everything else connect via sup you should change that from a LEFT JOIN to just a JOIN

Related

Wrong output by query in ms sql server

I have written a query in ms sql server in which I am using pivoting. As I am not familiar with pivoting I want to know where I am going wrong, as my query is not producing the desired output. My query is like this:
SELECT Name,ap,er,ft,vp
FROM (SELECT DISTINCT tbStudent.Name,
dbo.tbSubjects.SubCode,
dbo.fnTotalDays(dbo.tbAttendanceMaster.SubID,
dbo.tbStudent.StudentID) AS Total
FROM dbo.tbAttendance
INNER JOIN dbo.tbAttendanceMaster
ON dbo.tbAttendance.MasterAID = dbo.tbAttendanceMaster.AtdID
INNER JOIN dbo.tbStudent
ON dbo.tbAttendance.StID = dbo.tbStudent.StudentID
INNER JOIN dbo.tbSubjects
ON dbo.tbAttendanceMaster.SubID = dbo.tbSubjects.SubID
LEFT OUTER JOIN dbo.tbSemester
ON dbo.tbSubjects.SemID = dbo.tbSemester.SemID) sq
PIVOT(sum(Total) FOR SubCode IN(ap,er,ft,vp) ) AS pt
UNION ALL
SELECT Name ,ap ,er ,ft ,vp
FROM (SELECT DISTINCT tbStudent.Name,
dbo.tbSubjects.SubCode,
dbo.fnNoOfDays(dbo.tbAttendanceMaster.SubID,
dbo.tbStudent.StudentID) AS Present
FROM dbo.tbAttendance
INNER JOIN dbo.tbAttendanceMaster
ON dbo.tbAttendance.MasterAID = dbo.tbAttendanceMaster.AtdID
INNER JOIN dbo.tbStudent
ON dbo.tbAttendance.StID = dbo.tbStudent.StudentID
INNER JOIN dbo.tbSubjects
ON dbo.tbAttendanceMaster.SubID = dbo.tbSubjects.SubID
LEFT OUTER JOIN dbo.tbSemester
ON dbo.tbSubjects.SemID = dbo.tbSemester.SemID ) sq2
PIVOT(sum(Present) FOR SubCode IN(ap,er,ft,vp) ) AS pt2
It is giving me output like this:
Name Ep ER FT SQ
Amir 2 9 3 2
muzamil NULL 5 NULL
roof 2 9 3 7
Amir 0 9 3 1
muzamil NULL 5 NULL
roof 2 7 3 7
but I want output like this:
Name Ep ER FT SQ JB CQ LQ YC
Amir 2 9 3 2 0 9 3 1
muzamil NULL 5 NULL NULL 5 NULL NULL
roof 2 9 3 7 2 7 3 7
I want the last three rows which are the output of second query to show as the new columns JB, CQ, LQ and YC on the original three rows as shown in my table above.
There seem to be some mismatches in the column names in your query, you use SELECT Name,ap,er,ft,vp but the sample output lists Name Ep ER FT SQ, so you might have to adjust the answer below to fit your needs.
I think this query might work:
SELECT
Name,
MAX(ap) AS EP, MAX(er) AS ER,
MAX(ft) AS FT, MAX(vp) AS SQ,
MAX(jb) AS JB, MAX(cq) AS CQ,
MAX(lq) AS LQ, MAX(yc) AS YC
FROM (
SELECT
Name,
ap, er, ft, vp,
NULL AS JB, NULL AS CQ, NULL AS LQ, NULL AS YC
FROM (
SELECT DISTINCT
tbStudent.Name,
dbo.tbSubjects.SubCode,
dbo.fnTotalDays(dbo.tbAttendanceMaster.SubID,
dbo.tbStudent.StudentID) AS Total
FROM dbo.tbAttendance
INNER JOIN dbo.tbAttendanceMaster
ON dbo.tbAttendance.MasterAID = dbo.tbAttendanceMaster.AtdID
INNER JOIN dbo.tbStudent
ON dbo.tbAttendance.StID = dbo.tbStudent.StudentID
INNER JOIN dbo.tbSubjects
ON dbo.tbAttendanceMaster.SubID = dbo.tbSubjects.SubID
LEFT OUTER JOIN dbo.tbSemester
ON dbo.tbSubjects.SemID = dbo.tbSemester.SemID
) sq
PIVOT(SUM(Total) FOR SubCode IN (ap,er,ft,vp)
) AS pt
UNION ALL
SELECT
Name,
NULL AS ap, NULL AS er, NULL AS ft, NULL AS vp,
ap AS JB, er AS CQ, ft AS LQ, vp AS YC
FROM (
SELECT DISTINCT tbStudent.Name,
dbo.tbSubjects.SubCode,
dbo.fnNoOfDays(dbo.tbAttendanceMaster.SubID,
dbo.tbStudent.StudentID) AS Present
FROM dbo.tbAttendance
INNER JOIN dbo.tbAttendanceMaster
ON dbo.tbAttendance.MasterAID = dbo.tbAttendanceMaster.AtdID
INNER JOIN dbo.tbStudent
ON dbo.tbAttendance.StID = dbo.tbStudent.StudentID
INNER JOIN dbo.tbSubjects
ON dbo.tbAttendanceMaster.SubID = dbo.tbSubjects.SubID
LEFT OUTER JOIN dbo.tbSemester
ON dbo.tbSubjects.SemID = dbo.tbSemester.SemID
) sq2
PIVOT(SUM(Present) FOR SubCode IN (ap,er,ft,vp)
) AS pt2
) AS subquery GROUP BY Name

Sql Query to find sum from different tables

Hi i require a help in writing a query.
Tables are:
tblStandard1students
tblStandard2students
tblStandard1students
tblDivision
tblCandidateinfo
tblStandard1students,tblStandard2students,tblStandard1studentstbl contain information about students enrolled in standard 1,2 and 3
tblStandars1students
Candid admitted
1 Y
2 N
3 Y
tblDivision contains only 2 columns
ID Division
1 A
2 B
3 C
tblCandidateinfo
Candid gender Division
1 M 1
2 F 2
and so on...
Now I want the table like this
Division Students(Standard1) Students(Standard2) Students(Standard3)
M F M F M F
------------------------------------------------------------------------
A 1 0 0 0 0 1
B 2 2 3 3 4 4
C 1 0 0 0 0 0
I tried this following query:
SELECT Division,
( SELECT count(*)
FROM tblStandard1students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division) AS Students(Standard1),
( SELECT count(*)
FROM tblStandard2students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division) AS Students(Standard2),
( SELECT count(*)
FROM tblStandard3students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division ) AS Students(Standard3)
FROM tblDivision Z
but this is only half the query i din segregate it gender wise...help me to complete it.
;WITH combined AS
(
SELECT ci.Division, 'Students(Standard1) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard1students s ON ci.Candid = s.Candid
UNION ALL
SELECT ci.Division, 'Students(Standard2) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard2students s ON ci.Candid = s.Candid
UNION ALL
SELECT ci.Division, 'Students(Standard3) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard1studentstbl s ON ci.Candid = s.Candid
)
SELECT Division,
[Students(Standard1) M], [Students(Standard1) F],
[Students(Standard2) M], [Students(Standard2) F],
[Students(Standard3) M], [Students(Standard3) F]
FROM
(
SELECT d.Division, grp
FROM tblDivision d
LEFT OUTER JOIN combined c ON d.ID = c.Division
) x
PIVOT
(
COUNT(grp)
FOR grp IN ([Students(Standard1) M], [Students(Standard1) F],
[Students(Standard2) M], [Students(Standard2) F],
[Students(Standard3) M], [Students(Standard3) F])
) y
ORDER BY Division
SELECT divison.Division ,IFNULL(stander1.M,0),IFNULL(stander1.F,0) FROM test.tblDivision divison
Left join (SELECT division ,count( case gender when 'M' then 1 else null end) as M,count( case gender when 'F' then 1 else null end) as F
FROM
test.tblCandidateinfo tc inner join test.tblStandars1students ts1
ON tc.Candid=ts1.Candid
group by division) as stander1 on stander1.division= divison.id
group by divison.id
;
Insted of IFNULL use ISNULL and
take left join for all standar tables

Get Total Branch wise in SQL Server

SELECT b.BranchName ,
pm.AgreementValue
FROM dbo.Member AS m
INNER JOIN dbo.PlanMaster AS pm ON ( m.PlanId = pm.PlanId )
INNER JOIN dbo.Branch AS b ON ( b.BranchId = m.BranchId )
this is the result of above query
BranchName AgreementValue
------------------------------
abc 60000.00
abc 36000.00
abc 36000.00
xyz 20000.00
xyz 10000.00
now i want to get to total of AgreementValue BranchName wise..thanks for help
GROUP BY b.BranchName with SUM like so:
SELECT b.BranchName ,
SUM(pm.AgreementValue) TotalValue
FROM dbo.Member AS m
INNER JOIN dbo.PlanMaster AS pm ON ( m.PlanId = pm.PlanId )
INNER JOIN dbo.Branch AS b ON ( b.BranchId = m.BranchId )
GROUP BY b.BranchName;
If you are trying to get the total on each row, then use the window function for sum():
SELECT b.BranchName ,
pm.AgreementValue,
sum(pm.AgreementValue) over (partition by b.BranchName) as BranchTotal
FROM dbo.Member AS m
INNER JOIN dbo.PlanMaster AS pm ON ( m.PlanId = pm.PlanId )
INNER JOIN dbo.Branch AS b ON ( b.BranchId = m.BranchId )

SUM data only when COUNT(*) > 0

Here is what I have so far...
SELECT pr.[name], SUM(COALESCE(qm.iscompleted,0)) count_yes,
SUM(COALESCE(qm.iscompleted,1)) count_no,
COUNT(p.id) AS tot
FROM (aco.practices pr
left JOIN aco.patients_practices ppr ON (ppr.practiceid = pr.id)
left JOIN aco.patients p ON (p.id = ppr.patientid)
LEFT JOIN aco.qmheader qm ON (qm.patientid = p.id AND qm.practiceid = pr.id)
)
WHERE (pr.parentaco = 30982)
GROUP BY pr.[name]
ORDER BY pr.[name]
Here are some results
name count_yes count_no tot
name1 0 1 0
name2 0 1 0
name3 0 273 273
name4 0 114 114
For the most part it is correct, the only thing I need is to not SUM on the count_no if the tot is 0.
Is there a way to do this easily?
Thanks.
Change your select clause to:
SELECT pr.[name],
SUM(COALESCE(qm.iscompleted,0)) AS count_yes,
(case when COUNT(p.id) > 0 then
SUM(COALESCE(qm.iscompleted,1))
else
0 end) AS count_no,
COUNT(p.id) AS tot
Use the HAVING clause:
SELECT pr.[name], SUM(COALESCE(qm.iscompleted,0)) count_yes,
SUM(COALESCE(qm.iscompleted,1)) count_no,
COUNT(p.id) AS tot
FROM (aco.practices pr
left JOIN aco.patients_practices ppr ON (ppr.practiceid = pr.id)
left JOIN aco.patients p ON (p.id = ppr.patientid)
LEFT JOIN aco.qmheader qm ON (qm.patientid = p.id AND qm.practiceid = pr.id)
)
WHERE (pr.parentaco = 30982)
GROUP BY pr.[name]
HAVING COUNT(p.id) = 0
ORDER BY pr.[name]

SQL Query multiple rows into one, if criteria met

I am a novice at this, nor is this my data. We are trying to pull multiple records into one record for query results.
To simplify the tables and amount of data, the following two tables should be sufficient:
Table 1
PRVDR_NUM | RPT_REC_NUM
013 1234
014 4567
Table 2
RPT_REC_NUM | WKSHT_CD | LINE_NUM | ITM_VAL_NUM
1234 f1 3 30
1234 f1 9 3
1234 e2 100 100
4567 f1 3 20
4567 f1 9 8
4567 e2 100 100
The first part is to get all records where the ITM_NUM_CAL is between 25 and 50 for WKSHT_CD f1 and LINE_NUM 3, that ITM_NUM_VAL is revenue.
SELECT r.PRVDR_NUM as Provider,
r.RPT_REC_NUM as 'Report Record',
n.ITM_VAL_NUM as Revenue
FROM Table 1 r
left outer join Table 2 n on
r.RPT_REC_NUM = n.RPT_REC_NUM
WHERE (n.WKSHT_CD = 'f1') and (n.LINE_NUM = '3')
and (n.ITM_VAL_NUM > 25) and (n.ITM_VAL_NUM < 50)
and left(r.PRVDR_NUM, 2) in ('01','04','11','18','25','26','34','44','49')
So our results are:
Provider | Report Record | Revenue
013 1234 30
But we also want to be able to pull the corresponding ITM_VAL_NUM for WKSHT_CD f1 and LINE_NUM 9, which we'll call cost.
So the results should be:
Provider | Report Record | Revenue | Cost
013 1234 30 3
Much thanks in advance.
EDIT
I believe this is the final query I was looking for after some maneuvering and the addition of a new variable, CLMN_NUM, which is another column in table2.
SELECT r.PRVDR_NUM as Provider,
r.RPT_REC_NUM as 'Report Record',
n.ITM_VAL_NUM as Revenue,
n2.ITM_VAL_NUM as 'Cost',
n3.ITM_VAL_NUM as 'Visits'
FROM table1 r
LEFT OUTER JOIN table2 n on r.RPT_REC_NUM = n.RPT_REC_NUM
LEFT OUTER JOIN table2 n2 on n.WKSHT_CD = n2.WKSHT_CD
and n.RPT_REC_NUM = n2.RPT_REC_NUM and n2.LINE_NUM = 9
LEFT OUTER JOIN table2 n3 on r.RPT_REC_NUM = n3.RPT_REC_NUM
and n3.WKSHT_CD = 'e2' and n3.LINE_NUM = 100 and n3.CLMN_NUM = xxxx
WHERE (n.WKSHT_CD = 'f1')
AND (n.LINE_NUM = '3')
AND (n.ITM_VAL_NUM > 25)
AND (n.ITM_VAL_NUM < 50)
AND left(r.PRVDR_NUM, 2) in ('01','04','11','18','25','26','34','44','49')
A couple ways:
Subquery
SELECT r.PRVDR_NUM as Provider,
r.RPT_REC_NUM as 'Report Record',
n.ITM_VAL_NUM as Revenue
(SELECT ITM_VAL_NUM
FROM Table2
WHERE WKSHT_CD = n.WKSHT_CD
AND LINE_NUM = 9) AS Cost
FROM Table1 r
LEFT OUTER JOIN Table2 n on r.RPT_REC_NUM = n.RPT_REC_NUM
WHERE (n.WKSHT_CD = 'f1')
AND (n.LINE_NUM = '3')
AND (n.ITM_VAL_NUM > 25)
AND (n.ITM_VAL_NUM < 50)
AND left(r.PRVDR_NUM, 2) in ('01','04','11','18','25','26','34','44','49')
Another JOIN
SELECT r.PRVDR_NUM as Provider,
r.RPT_REC_NUM as 'Report Record',
n.ITM_VAL_NUM as Revenue
n2.Cost
FROM Table1 r
LEFT OUTER JOIN Table2 n on r.RPT_REC_NUM = n.RPT_REC_NUM
LEFT OUTER JOIN Table2 n2 on n.WKSHT_CD = n2.WKSHT_CD
AND LINE_NUM = 9
WHERE (n.WKSHT_CD = 'f1')
AND (n.LINE_NUM = '3')
AND (n.ITM_VAL_NUM > 25)
AND (n.ITM_VAL_NUM < 50)
AND left(r.PRVDR_NUM, 2) in ('01','04','11','18','25','26','34','44','49')
You can by doing a CASE/WHEN on your columns in question, but allowing BOTH values of LINE_NUM in your where too... Using the COALESCE will prevent NULL values in case no records for one side, the other or both for revenue/costs respectively. You could just use the same consideration for any other "LINE_NUM" values you wanted to include too.
SELECT
r.PRVDR_NUM as Provider,
r.RPT_REC_NUM as 'Report Record',
COALESCE( CASE WHEN n.LINE_NUM = 3 THEN n.ITM_VAL_NUM ELSE 0 END, 0 ) as Revenue,
COALESCE( CASE WHEN n.LINE_NUM = 9 THEN n.ITM_VAL_NUM ELSE 0 END, 0 ) as Costs
from
Table_1 r
left join Table_2 n
on r.RPT_REC_NUM = n.RPT_REC_NUM
AND n.WKSHT_CD = 'f1'
AND n.LINE_NUM in ( '3', '9')
AND n.ITM_VAL_NUM between 25 and 50
where
left(r.PRVDR_NUM, 2) in ('01','04','11','18','25','26','34','44','49')
SELECT
Provider = r.PRVDR_NUM,
[Report Record] = r.RPT_REC_NUM,
Revenue = MIN(CASE n.LINE_NUM WHEN '3' THEN n.ITM_VAL_NUM),
Cost = MIN(CASE n.LINE_NUM WHEN '9' THEN n.ITM_VAL_NUM)
FROM Table1 r
INNER JOIN Table2 n ON r.RPT_REC_NUM = n.RPT_REC_NUM
WHERE n.WKSHT_CD = 'f1' AND n.LINE_NUM IN ('3', '9')
AND n.ITM_VAL_NUM > 25 AND n.ITM_VAL_NUM < 50
AND LEFT(r.PRVDR_NUM, 2) IN ('01','04','11','18','25','26','34','44','49')
GROUP BY
r.PRVDR_NUM,
r.RPT_REC_NUM