Using two Count() functions without changing the results - sql

SELECT CARRIER.CARRIERID, PLAN.PLANID, PLNDESCRIPTION,
COUNT(MEMBER.PLANID) AS MBRCNT
FROM CARRIER
LEFT OUTER JOIN PLAN
ON CARRIER.CARRIERID = PLAN.CARRIERID
LEFT OUTER JOIN MEMBER
ON PLAN.PLANID = MEMBER.PLANID
GROUP BY CARRIER.CARRIERID, PLAN.PLANID, PLNDESCRIPTION
ORDER BY CARRIER.CARRIERID;
results in
CARR PLANID PLNDESCRIPTION MBRCNT
---- ---------- ----------------------------------- ----------
ANTH 4 Single SuperMed 6
ANTH 5 2-Party SuperMed 4
ANTH 6 Family SuperMed 7
BCBS 1 Single Basic Medical 9
BCBS 2 2-Party Basic Medical 15
BCBS 3 Family Basic Medical 11
DLT 7 Single Dental Only 6
DLT 8 Family Dental Only 0
MM 10 Single SuperMed with Dental 5
MM 11 2-Party SuperMed with Dental 0
MM 12 Family SuperMed with Dental 2
NWD 9 Life Only 2
PHC 0
and
SELECT CARRIER.CARRIERID, COUNT(PLAN.CARRIERID)
FROM CARRIER
LEFT OUTER JOIN PLAN
ON CARRIER.CARRIERID = PLAN.CARRIERID
LEFT OUTER JOIN MEMBER
ON PLAN.PLANID = MEMBER.PLANID
GROUP BY CARRIER.CARRIERID
ORDER BY CARRIER.CARRIERID;
result in
CARR COUNT(PLAN.CARRIERID)
---- ---------------------------------------
ANTH 17
BCBS 35
DLT 7
MM 8
NWD 2
PHC 0
How can I combine these to get all of the rows next to each other?

I think you just want analytic functions:
SELECT c.CARRIERID, p.PLANID, p.PLNDESCRIPTION,
COUNT(m.PLANID) AS MBRCNT,
SUM(COUNT(m.PLANID)) OVER (PARTITION BY c.CARRIERID) as CNT_2
FROM CARRIER c LEFT JOIN
PLAN p
ON c.CARRIERID = p.CARRIERID LEFT JOIN
MEMBER m
ON p.PLANID = m.PLANID
GROUP BY c.CARRIERID, p.PLANID, p.PLNDESCRIPTION
ORDER BY c.CARRIERID;

One option is to full outer join them together
with firstCount as (
SELECT CARRIER.CARRIERID, PLAN.PLANID, PLNDESCRIPTION,
COUNT(MEMBER.PLANID) AS MBRCNT
FROM CARRIER
LEFT OUTER JOIN PLAN
ON CARRIER.CARRIERID = PLAN.CARRIERID
LEFT OUTER JOIN MEMBER
ON PLAN.PLANID = MEMBER.PLANID
GROUP BY CARRIER.CARRIERID, PLAN.PLANID, PLNDESCRIPTION
ORDER BY CARRIER.CARRIERID
)
secondCount as (
SELECT CARRIER.CARRIERID, COUNT(PLAN.CARRIERID) as count
FROM CARRIER
LEFT OUTER JOIN PLAN
ON CARRIER.CARRIERID = PLAN.CARRIERID
LEFT OUTER JOIN MEMBER
ON PLAN.PLANID = MEMBER.PLANID
GROUP BY CARRIER.CARRIERID
ORDER BY CARRIER.CARRIERID
)
select coalesce(firstCount.carrierId, secondCount.carrierId) as carrierId,
firstCount.PLANID,
firstCount.PLNDESCRIPTION,
firstCount.MBRCNT,
secondCount.Count
from firstCount
full outer join secondCount on firstCount.CarrierId = secondCount.CarrierId

Related

SQL query doesnt return expected values

I have 3 tables. 1st table stores coil information, 2nd table store coil information in transport and 3rd stores reserved coils.
coils
ID
SERIAL
COLOR
MATERIAL
STATUS
1
12345
5
1
2
2
12346
4
1
3
3
12347
3
1
2
coils_in_transport
ID
SERIAL
COLOR
MATERIAL
STATUS
1
f34S5
5
1
2
2
A23GG6
4
1
3
3
ff2S147
3
1
2
reserved_coils
ID
NUMBER
QUANTITY
START
END
1
12345
25
2022-05-01
2023-05-01
3
12347
252
2022-01-01
2023-05-01
4
A23GG6
33
2022-04-01
2023-05-01
5
ff2S147
35
2022-08-01
2023-05-01
I need to write query that will get all reserved coils (reserved_coils) that has status 2 and for each coil I need to join tables for materials and colors
material
ID
NAME
1
color
ID
NAME
I wrote query but it doesn't show coils in transport that are reserved, here is what I tried
SELECT a.QUANTITY, a.START, a.END, b.name, m.name
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material b ON b.material = b.id
where b.status = 2 and c.status = 2
To get all coils and colis_in_transport you need to use UNION for SELECT statements for both tables, each filtered by status value, which should be equal to 2. Then you need to do a JOIN between reserved_coils and the result of UNION to filter out reserved_coils rows.
Your query would be like this
SELECT
r.quantity,
r.start,
r.[end],
c.serial,
material.name AS material,
color.name AS color
FROM reserved_coils r
JOIN (
SELECT * FROM coils WHERE status = 2
UNION
SELECT * FROM coils_in_transport WHERE status = 2
) c ON r.number = c.serial
LEFT JOIN material ON material.id = c.material
LEFT JOIN color ON color.id = c.color
Demo
If you want left join twice on same table, this might help
SELECT a.QUANTITY, a.START, a.[END], isnull(b.serial,c.serial) serial,isnull(c1.name,c2.name) color, isnull(m.name,n.name) material
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material n ON c.material = n.id
LEFT JOIN color c1 on b.color=c1.id
LEFT JOIN color c2 on c.color=c2.id
where isnull(b.status,c.status) = 2
DB<>Fiddle

SQL Queue to get workload in 2 weeks [SQL Server]

Currently, the queue shows me the workload of products in a oven and for product which are in the oven too, but actually for some hours in a test outside of the oven.
I count the h with "gesamt" for each product -> this show me how Long they stay already in the oven. Mostly the products stay 1000h in the oven its defined in "Zielgröße" in the db.
What I want is that the queue should show me the workload of the oven for the next 2 weeks as a prediction (336h). Thats all "gesamt" which is over "Zielgröße" (mostly 1000) not shown in the queue maybe handled in a temporary table or whatever.
Is it possible to handle this in Micrososft SQL Server?
Here is the code:
SELECT TesterID,Name, TesterNr, COUNT(Name) as Anzahl, gesamt FROM
(SELECT AllgemeineAngaben.QualiID,
Bezeichnung,
AnzModule,
Tester.Name, TesterNr,
Testname,
v_gesamtBerechnungLaufend.TestaufstellungID,
lastRO,
gesamt,
v_gesamtBerechnungLaufend.Einheit,
v_gesamtBerechnungLaufend.PlanID,
v_gesamtBerechnungLaufend.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnungLaufend on
AllgemeineAngaben.QualiID = v_gesamtBerechnungLaufend.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnungLaufend.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnungLaufend.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
Where Tester.Name = 'KPS02'
UNION ALL
SELECT AllgemeineAngaben.QualiID,
Bezeichnung, AnzModule, Tester.Name, TesterNr,
Testname,
Testaufstellung.TestaufstellungID,
v_gesamtBerechnung.gesamt as lastRO,
v_gesamtBerechnung.gesamt,
v_gesamtBerechnung.Einheit,
v_gesamtBerechnung.PlanID,
v_gesamtBerechnung.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnung on
AllgemeineAngaben.QualiID = v_gesamtBerechnung.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnung.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnung.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
WHERE Testaufstellung.fertig ='0'
AND Testaufstellung.aktiv ='1'
AND Testaufstellung.Zielgröße > v_gesamtBerechnung.gesamt
AND Tester.Name = 'KPS02'
AND v_gesamtBerechnung.TestaufstellungID not in (Select TestaufstellungID from DB.dbo.v_gesamtBerechnungLaufend)) x
group by TesterID, Name, TesterNr, gesamt
Here the table to show in an example what I want
actual workload
TesterID Name TesterNr Anzahl gesamt
-------------- ------- ---------- ----------- -----------
Product1 8 KPS02 2 1 209
Product2 8 KPS02 2 1 216
Product3 8 KPS02 2 1 816
Product4 8 KPS02 2 1 835
workload in 2 weeks
TesterID Name TesterNr Anzahl gesamt
-------------- ------- ---------- ----------- -----------
Product1 8 KPS02 2 1 545
Product2 8 KPS02 2 1 552
the last recors are over 1000 Zielgröße, so just dont show them in the prediction queue
Product3 8 KPS02 2 1 1152
Product4 8 KPS02 2 1 1171
I hope you guys can follow me. Thanks for your help.
I'll edit this answer until it's solved, but here's my first attempt:
SELECT TesterID,Name, TesterNr, COUNT(Name) as Anzahl, gesamt + 336 as gesamt
FROM
(SELECT AllgemeineAngaben.QualiID,
Bezeichnung,
AnzModule,
Tester.Name, TesterNr,
Testname,
v_gesamtBerechnungLaufend.TestaufstellungID,
lastRO,
gesamt,
v_gesamtBerechnungLaufend.Einheit,
v_gesamtBerechnungLaufend.PlanID,
v_gesamtBerechnungLaufend.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnungLaufend on
AllgemeineAngaben.QualiID = v_gesamtBerechnungLaufend.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnungLaufend.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnungLaufend.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
Where Tester.Name = 'KPS02'
UNION ALL
SELECT AllgemeineAngaben.QualiID,
Bezeichnung, AnzModule, Tester.Name, TesterNr,
Testname,
Testaufstellung.TestaufstellungID,
v_gesamtBerechnung.gesamt as lastRO,
v_gesamtBerechnung.gesamt,
v_gesamtBerechnung.Einheit,
v_gesamtBerechnung.PlanID,
v_gesamtBerechnung.TesterID
FROM DB.dbo.AllgemeineAngaben inner join
DB.dbo.v_gesamtBerechnung on
AllgemeineAngaben.QualiID = v_gesamtBerechnung.QualiID inner join
DB.dbo.Tester on
Tester.TesterID = v_gesamtBerechnung.TesterID inner join
DB.dbo.Testaufstellung on
Testaufstellung.TestaufstellungID = v_gesamtBerechnung.TestaufstellungID inner join
DB.dbo.Testnamen on Testnamen.TestnameID = Testaufstellung.TestnameID
WHERE Testaufstellung.fertig ='0'
AND Testaufstellung.aktiv ='1'
AND Testaufstellung.Zielgröße > v_gesamtBerechnung.gesamt
AND Tester.Name = 'KPS02'
AND v_gesamtBerechnung.TestaufstellungID not in (Select TestaufstellungID from DB.dbo.v_gesamtBerechnungLaufend)) x
group by TesterID, Name, TesterNr, gesamt
) A
WHERE gesamt + 336 < 1000
It seems to me like all you need to do is add 336 to the current values and then filter out anything less than 1000.

SUM and ORDER BY

I have this table
Pupil ID Fname Lname Form House Week Nr Data
104 fname1 lname1 Year 5W Junior Frobisher 3 5
106 fname2 lname2 Year 4W Junior Grenville 2 5
106 fname2 lname2 Year 4W Junior Grenville 3 4
106 fname2 lname2 Year 4W Junior Grenville 4 3
106 fname2 lname2 Year 4W Junior Grenville 5 5
107 fname3 lname3 Year 5W Junior Grenville 1 1
107 fname3 lname3 Year 5W Junior Grenville 2 3
107 fname3 lname3 Year 5W Junior Grenville 3 5
107 fname3 lname3 Year 5W Junior Grenville 4 1
SELECT PPD.PupilID, PPD.Forename, PPD.Surname, FL.[Description] AS 'Form', HL.[Description] AS 'House', CAST(REPLACE(CM.ColumnTitle, 'Week ', '') AS INT) AS 'WeekNo',CAST(MSDN.Data AS INT) AS 'Data', SUM(CAST(MSDN.Data AS INT)) AS 'Total'
FROM CurrentPupil
INNER JOIN PupilPersonalDetails AS PPD ON PPD.PupilID = CurrentPupil.PupilID
INNER JOIN PupilCurrentSchool AS PCS ON PCS.PupilID = PPD.PupilID
INNER JOIN SchoolLookupDetails AS FL ON PCS.Form = FL.LookupDetailsID AND FL.LookupID = 1002
INNER JOIN SchoolLookupDetails AS HL ON PCS.House = HL.LookupDetailsID AND HL.LookupID = 1001
INNER JOIN MarksheetDataNumeric AS MSDN ON MSDN.PupilID = PPD.PupilID
INNER JOIN ColumnsMaster AS CM ON CM.ColumnID = MSDN.ColumnID AND CM.ColumnTitle LIKE '%week%'
INNER JOIN ClusterMaster AS CLM ON CLM.ClusterID = SUBSTRING(PPD.SchoolID, 0, 4)
INNER JOIN ColumnReportingPeriods AS CRP ON CRP.ColumnID = CM.ColumnID
INNER JOIN ReportingPeriods AS RP ON RP.AcademicYear = CLM.CurrentAcademicYear AND RP.ReportingPeriodID = CRP.ReportingPeriodID
WHERE ('%wc%' = '%wc%')
GROUP BY PPD.PupilID
I am trying to SUM the following column
CAST(MSDN.Data AS INT) AS 'Data'
and add a new one as a total points for each ID (pupil)
CAST(MSDN.Data AS INT) AS 'Data', SUM(CAST(MSDN.Data AS INT)) AS 'Total',
(I think it is right!)
but the outcome is:
Column PupilPersonalDetails.ForeName is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Start from this:
SELECT PPD.PupilID
,PPD.Forename
,PPD.Surname
,SUM(MSDN.Data) 'Total'
FROM CurrentPupil
INNER JOIN PupilPersonalDetails PPD ON PPD.PupilID=CurrentPupil.PupilID
INNER JOIN PupilCurrentSchool PCS ON PCS.PupilID=PPD.PupilID
INNER JOIN SchoolLookupDetails FL ON PCS.Form=FL.LookupDetailsID AND FL.LookupID=1002
INNER JOIN SchoolLookupDetails HL ON PCS.House=HL.LookupDetailsID AND HL.LookupID=1001
INNER JOIN MarksheetDataNumeric MSDN ON MSDN.PupilID=PPD.PupilID
INNER JOIN ColumnsMaster CM ON CM.ColumnID=MSDN.ColumnID AND CM.ColumnTitle LIKE '%week%'
INNER JOIN ClusterMaster CLM ON CLM.ClusterID=SUBSTRING(PPD.SchoolID,0,4)
INNER JOIN ColumnReportingPeriods CRP ON CRP.ColumnID=CM.ColumnID
INNER JOIN ReportingPeriods RP ON RP.AcademicYear=CLM.CurrentAcademicYear AND RP.ReportingPeriodID=CRP.ReportingPeriodID
WHERE ('%wc%'='%wc%')
GROUP BY PPD.PupilID
,PPD.Forename
,PPD.Surname
If you want to have more columns in the result you can add them, but since you are using an aggregation function SUM you have to have all these columns - except the one you are aggregating (summing in this case) - mentioned in the GROUP BY clause.

Fetch Max Value

TABLE Laptop_Shift_Departments
id Laptop_ID Curr_department Pre_Department
-----|----------|-----------------|----------------
9 71 4 3
10 68 4 3
11 71 5 4
12 68 5 4
User only search PO Number and against this PO_Num there are 2 laptops (Laptop_ID)
Above is my table now i want to get MAX value Against this laptop_ID ID
I have tried this:
SELECT LD.ID AS Laptop_ID,ld.GulfITBarcode,po.ID as PO_ID,PO.PO_Number as PO_Number,D.Department,
D.ID as Crr_DepID1,d2.Department,D2.ID as Pre_DepID2
FROM PO_PURCHASEORDER PO
INNER JOIN PO_Laptop_Master LM
ON LM.PO_ID = PO.ID
INNER JOIN PO_LaptopDetail LD
ON LD.LapTop_Master_ID = LM.ID
INNER JOIN Laptop_Shift_Departments DP
ON DP.Laptop_Detail_ID = LD.ID
inner join Laptop_Departments d
on d.ID = DP.Current_Dep_ID
inner join Laptop_Departments d2
on d2.ID = DP.Previous_Dep_ID
WHERE PO_NUMBER = '5258'
AND
LD.ID IN (select Max(cSh.id) from Laptop_Shift_Departments cSh)
But it is not working
MY output should be like this:
id Laptop_ID Curr_department Pre_Department
-----|----------|-----------------|----------------
11 71 5 4
12 68 5 4
You'll want to use the 'Group By' function at the end of the fields you want to group by and the 'Max' function in the Select on the columns you want the 'Max' (or 'Min' or 'Avg'). Should look something like this:
SELECT
LD.ID AS Laptop_ID
,ld.GulfITBarcode
,po.ID as PO_ID
,PO.PO_Number as PO_Number
,D.Department
,MAX(D.ID) as Crr_DepID1
,d2.Department
,MAX(D2.ID) as Pre_DepID2
FROM PO_PURCHASEORDER PO
INNER JOIN PO_Laptop_Master LM
ON LM.PO_ID = PO.ID
INNER JOIN PO_LaptopDetail LD
ON LD.LapTop_Master_ID = LM.ID
INNER JOIN Laptop_Shift_Departments DP
ON DP.Laptop_Detail_ID = LD.ID
inner join Laptop_Departments d
on d.ID = DP.Current_Dep_ID
inner join Laptop_Departments d2
on d2.ID = DP.Previous_Dep_ID
WHERE PO_NUMBER = '5258'
AND LD.ID IN (select Max(cSh.id) from Laptop_Shift_Departments cSh)
AND DP.Current_Dep_ID = 5
GROUP BY
LD.ID
,ld.GulfITBarcode
,po.ID
,PO.PO_Number
,D.Department
,d2.Department
(Having not seen the table structure I'm not sure as to the rest of the query. Hope this helps.)

Oracle Outer join with 0 value return for non existing rows

I have 2 tables
Person
--------------------
id name dept_id
---------------------
1 x 1
2 y 1
3 z 2
Feedback
------------------------------------
person_id f_date positive negative
------------------------------------
1 2014-05-05 10 4
1 2014-05-15 5 3
2 2014-05-11 3 8
Now my query is
SELECT p.id,
nvl(sum(positive),0) AS pf,
nvl(sum(negative),0) AS nf
FROM person p
LEFT OUTER JOIN feedback f ON p.id = f.person_id
WHERE f_date BETWEEN to_date('2014-05-04', 'YYYY-MM-DD')
AND to_date('2014-05-16', 'YYYY-MM-DD')
GROUP BY p.id
ORDER BY p.id;
I expect to see
id pf nf
---------------
1 15 7
2 3 8
3 0 0
but I don't see the the data for 3. In fact the data i get is only if the rows exist in feedback table as if its an equi join.
Your WHERE clause is turning the outer join into an inner join. The solution is to move the condition to the ON clause:
SELECT p.id, nvl(sum(positive),0) as pf, nvl(sum(negative),0) as nf
FROM person p left outer JOIN
feedback f
on p.id = f.person_id and
f.f_date between to_date('2014-05-04', 'YYYY-MM-DD') AND to_date('2014-05-16', 'YYYY-MM-DD')
GROUP BY p.id
ORDER BY p.id;