Using some column data for values and some for ID - sql

Slowly but surely I'm getting the hang of this. I created a report using the following query, which works perfectly. I'll give an example of the result below the query.
Select p.parent_program_id, p.program_id, p.name, p.copyright, p.active_flag,
max(Case when c.category_id = 36261 Then 'X' Else ' ' End) As CC_Indicator,
max(Case when c1.category_id = 36362 Then 'X' Else ' ' End) As CC_Badge,
max(Case when c2.category_id = 43221 Then 'X' Else ' ' End) As CC_Solution
From tbl_program p
Join xref_category_program xcp
On p.program_id=xcp.program_id
left Join tbl_category c
On xcp.category_id=c.category_id and c.category_id = 36261
left Join tbl_category c1
On xcp.category_id=c1.category_id and c1.category_id = 36362
left Join tbl_category c2
On xcp.category_id=c2.category_id and c2.category_id = 43221
where xcp.category_id in(36261,36362,43221)
group by p.program_id, p.name, p.copyright, p.active_flag, p.parent_program_id
Order by p.program_id
The results look like this (leaving out some unimportant columns for brevity's sake):
P.ParentProgramID P.ProgramID CC_Indicator CC_Badge CC_Solution
00001 12111 X
null 20200 X X X
null 00001 X X
The Indicator/Badge/Solution is identified by a category id. Now the people requesting this report want it sorted by company, which are also assigned category ids in the same column.
Assuming something like xcp.category_id values for company were 11111/22222/33333/44444, how would I put that in another column in this report in an order decided by the receivers of the report?
Something that looked like this, assuming a total of 6 records...
P.ParentProgramID P.ProgramID CC_Indicator CC_Badge CC_Solution Region
00001 12111 X 44444
null 20200 X X X 44444
null 00001 X X 22222
null 32332 X 11111
null 44215 X X 11111
null 84425 X 33333
second effort, described as rudimentary below...
Select p.parent_program_id, p.program_id, p.name, p.copyright, p.active_flag,
max(decode(c.category_id,36261,'X','')) As CC_Indicator,
max(decode(c1.category_id,36362,'X','')) As CC_Badge,
max(decode(c2.category_id,43221,'X','')) As CC_Solution,
max(decode(c3.category_id,6321,'US','')) As US,
max(decode(c4.category_id,6081,'CA','')) As CA,
max(decode(c5.category_id,35061,'GS','')) As GS
From tbl_program p Join xref_category_program xcp On p.program_id=xcp.program_id
left Join tbl_category c On xcp.category_id=c.category_id and c.category_id = 36261
left Join tbl_category c1 On xcp.category_id=c1.category_id and c1.category_id = 36362
left Join tbl_category c2 On xcp.category_id=c2.category_id and c2.category_id = 43221
left Join tbl_category c3 On xcp.category_id=c3.category_id and c3.category_id = 6321
left Join tbl_category c4 On xcp.category_id=c4.category_id and c4.category_id = 6081
left Join tbl_category c5 On xcp.category_id=c5.category_id and c5.category_id = 35061
where xcp.category_id in(36261,36362,43221,6321,6081,35061)
group by p.program_id, p.name, p.copyright, p.active_flag, p.parent_program_id
Order by p.program_id

I think you can simplify your query a bit, as follows:
Select p.parent_program_id,
p.program_id,
p.name,
p.copyright,
p.active_flag,
max(decode(c.category_id,36261,'X','')) As CC_Indicator,
max(decode(c.category_id,36362,'X','')) As CC_Badge,
max(decode(c.category_id,43221,'X','')) As CC_Solution,
max(decode(c.category_id,6321, 'US','')) As US,
max(decode(c.category_id,6081, 'CA','')) As CA,
max(decode(c.category_id,35061,'GS','')) As GS
From tbl_program p
INNER Join xref_category_program xcp
On p.program_id = xcp.program_id
INNER Join tbl_category c
On xcp.category_id = c.category_id
where xcp.category_id in (36261, 36362, 43221, 6321, 6081, 35061)
group by p.program_id, p.name, p.copyright, p.active_flag, p.parent_program_id
Order by p.program_id
I don't think you need the multiple joins of TBL_CATEGORY - one should do it, as you're identifying which categories you want in the WHERE clause.
I'm still at something of a loss as to getting the region ID's in. It seems that most of the basic data for this query (PROGRAM_ID, etc) comes from TBL_PROGRAM. Is there a column on TBL_PROGRAM which identifies the region? You can always make a second join of XREF_CATEGORY_PROGRAM or TBL_CATEGORY, but without knowing what column in the other tables identifies the region I can't help you understand how to get the region data joined in.
Share and enjoy.

Related

sql subquery join group by

I am trying to get a list of our users from our database along with the number of people from the same cohort as them - which in this case is defined as being from the same medical school at the same time.
medical_school_id is stored in the doctor_record table
graduation_dt is stored in the doctor_record table as well.
I have managed to write this query out using a subquery which does a select statement counting the number of others for each row but this takes forever. My logic is telling me that I ought to run a simple GROUP BY query once first and then somehow JOIN the medical_school_id on to that.
The group by query is as follows
select count(ca.id) , cdr.medical_school_id, cdr.graduation_dt
from account ca
LEFT JOIN doctor cd on ca.id = cd.account_id
LEFT JOIN doctor_record cdr on cd.gmc_number = cdr.gmc_number
GROUP BY cdr.medical_school_id, cdr.graduation_dt
The long select query is
select a.id, a.email , dr.medical_school_id,
(select count(ba.id) from account ba
LEFT JOIN doctor bd on ba.id = bd.account_id
LEFT JOIN doctor_record bdr on bd.gmc_number = bdr.gmc_number
WHERE bdr.medical_school_id = dr.medical_school_id AND bdr.graduation_dt = dr.graduation_dt) AS med_count,
from account a
LEFT JOIN doctor d on a.id = d.account_id
LEFT JOIN doctor_record dr on d.gmc_number = dr.gmc_number
If you could push me in the right direction that would be amazing
I think you just want window functions:
select a.id, a.email, dr.medical_school_id, dr.graduation_dt,
count(*) over (partition by dr.medical_school_id, dr.graduation_dt) as cohort_size
from account a left join
doctor d
on a.id = d.account_id left join
doctor_record dr
on d.gmc_number = dr.gmc_number;
Using your same code for group by:
SELECT * FROM (
(
SELECT acc.[id]
, acc.[email]
FROM
account acc
LEFT JOIN
doctor doc
ON
acc.id = doc.account_id
LEFT JOIN
doctor_record doc_rec
ON
doc.gmc_number = doc_rec.gmc_number
) label
LEFT JOIN
(
SELECT count(acco.id)
, doc_reco.medical_school_id
, doc_reco.graduation_dt
FROM
account acco
LEFT JOIN
doctor doct
ON
acco.id = doct.account_id
LEFT JOIN
doctor_record doc_reco
ON
doct.gmc_number = doc_reco.gmc_number
GROUP BY
doc_reco.medical_school_id,
doc_reco.graduation_dt
) count
ON
count.[medical_school_id]=label.[medical_school_id]
AND
count.[graduation_dt]=label.[graduation_date]
)
how about something like this?
select a.doctor_id
, count(*) - 1
from doctor_record a
left join doctor_record b on a.medical_school_id = b.medical_school_id
and a.graduation_dt = b.graduation_dt
group by a.doctor_id
Subtract 1 from the count so that you're not counting the doctor in the "other folks in same cohort" number
I'm defining "same cohort" as "same medical school & graduation date".
I'm unclear on what GMC number is and how it is related. Is it something to do with cohort?

SQL count in select query

I have a sql query that creates a label in a cab file for a shopping company. I want to include the amount of packages in an order, some have multiple.
Each returns line in my select query has an I’d and contains a package but I need to count them.
So I have:
Name Email Weight Price ID
Joe B J#.com 10 12.5. 1
Joe B J#.com 10 12.5. 1
Joe C JC#.com 10 14.5. 2
How can I count the ID’s to return a column called pieces and in this example it would be 2 for ID 1 and 1 for ID 2
Thanks
James
enter code here
Select
'WPX' As 'Product Code',
delivery_header.dh_datetime As 'Shipment Date',
'G' As 'Shipment Type',
order_header_detail.ohd_delivery_email As 'Receiver Email Address',
variant_detail.vad_weight As 'Shipment Weight in KG',
(lots of other fields....)
delivery_header.dh_number As 'Shippers Reference',
(SELECT Count(*)
FROM delivery_header
WHERE
dh_number = OU.dh_number
) As 'Number of Pieces',
From delivery_line_item Inner Join
delivery_header On delivery_header.dh_id = delivery_line_item.dli_dh_id
Inner Join
order_line_item On delivery_line_item.dli_oli_id = order_line_item.oli_id
Inner Join
variant_detail On variant_detail.vad_id = order_line_item.oli_vad_id
Inner Join
order_header On order_header.oh_id = order_line_item.oli_oh_id Inner Join
stock_location On stock_location.sl_id = order_line_item.oli_sl_id Inner Join
customer_detail On customer_detail.cd_id = order_header.oh_cd_id Inner Join
order_header_detail On order_header.oh_id = order_header_detail.ohd_oh_id
Left Join
order_header_analysis On order_header.oh_id = order_header_analysis.oha_oh_id
Left Join
order_customer_analysis On order_header.oh_id =
order_customer_analysis.oca_oh_id Left Join
order_delivery_analysis On order_header.oh_id =
order_delivery_analysis.oda_oh_id Left Join
order_line_analysis On order_line_item.oli_id = order_line_analysis.ola_oli_id
Left Join
order_line_product_analysis On order_line_item.oli_id =
order_line_product_analysis.olpa_oli_id Left Join
order_line_variant_analysis On order_line_item.oli_id =
order_line_variant_analysis.olva_oli_id Inner Join
product_detail On product_detail.pd_id = variant_detail.vad_pd_id Inner Join
delivery_method On delivery_method.dm_id = order_header_detail.ohd_dm_id
Inner Join
delivery_method [Delivery Method] On [Delivery Method].dm_id =
order_header_detail.ohd_dm_id Inner Join
currency On currency.c_id = order_header.oh_c_id And currency.c_id =
delivery_method.dm_c_id And currency.c_id = [Delivery Method].dm_c_id
Where
delivery_header.dh_number IN (199364,199363,199362,199360)
Order By delivery_header.dh_number
You can use GROUP BY with COUNT like this:
SELECT ID, COUNT(*) as count FROM tbl GROUP BY ID
What I understood from your question is that, you are looking for output like
Name Email Weight Price ID Pieces
Joe B J#.com 10 12.5. 1 2
Joe B J#.com 10 12.5. 1 2
Joe C JC#.com 10 14.5. 2 1
Using following query you should get the desired output in most of the DBMS.
SELECT NAME,
EMAIL,
WEIGHT,
PRICE,
ID,
(SELECT Count(*)
FROM <YOUR_TABLE_NAME>
WHERE ID= OU.ID) AS Pieces
FROM <YOUR_TABLE_NAME> OU
Similar Query for MS SQL Server can be
SELECT NAME, EMAIL,WEIGHT , Price, ID,CT.Pieces
FROM <YOUR_TABLE_NAME> OU
CROSS APPLY
(
SELECT COUNT(*) AS Pieces FROM <YOUR_TABLE_NAME> IU WHERE OU.ID=IU.ID
)CT

Return rows where a customer bought things on same day

Can someone help me with the rest of my Query.
This query gives me Customer, AdressNr, Date, Employee, Article, ActivityNr
from all the sales in my Company.
SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS Date,
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM
My goal is to filter this so i get only rows back where the customer has bought more then 1 Thing on the same day. It doesn't matter if a customer bought the same Article twice on the same day. I want too see this also.
It's to complicated to write some SQL Fiddle for you but in this Picture you can see what my goal is. I want to take away all rows with an X on the left side and thoose with a Circle i want to Keep.
As I don't speak German, I won't target this specifically to your SQL. But see the following quasi-code for a similar example that you should be able to apply to your own script.
SELECT C.CustomerName, O.OrderDate, O.OrderNumber
FROM CUSTOMER C
JOIN ORDERS O ON O.Customer_ID = C.Customer_ID
JOIN
(SELECT Customer_ID, OrderDate
FROM ORDERS
GROUP BY Customer_ID, OrderDate
HAVING COUNT(*) > 1) SRC
ON SRC.Customer_ID = O.Customer_ID AND SRC.OrderDate = O.OrderDate
In the script above, the last query (a subquery) would only return results where a customer had more than one order in a given day. By joining that to your main query, you would effectively produce the result asked in the OP.
Edit 1:
Regarding your comment below, I really recommend just going over your datamodel, trying to understand what's happening here, and fixing it on your own. But there is an easy - albeit hardly optimal solution to this by just using your own script above. Note, while this is not disastrous performance-wise, it's obviously not the cleanest, most effective method either. But it should work:
;WITH CTE AS (SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS [Date],
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM)
SELECT C.*
FROM CTE C
JOIN (Select CustomerNr, [Date]
FROM CTE B
GROUP BY CustomerNr, [Date]
HAVING COUNT(*) > 1) SRC
ON SRC.CustomerNr = C.CustomerNr AND SRC.[Date] = C.[Date]
This should work directly. But as I said, this is an ugly workaround where we're basically all but fetching the whole set twice, as opposed to just limiting the sub query to just the bare minimum of necessary tables. Your choice. :)
Tried that also and it didnt work. I also made a new query trying to Keep it so simple as possible and it doesnt work either. It still give me Single values back..
SELECT p.Datum,a.AufgabenNrCRM,auf.Kunde FROM CRM_Aufgaben a
LEFT JOIN ZUS_Therapie_Positionen p ON p.Id_Aktivitaet = a.AufgabenNrCRM
LEFT JOIN PRO_Auftraege auf ON auf.AuftragNrPRO = a.AuftragNrPRO
LEFT JOIN
(SELECT pa.Datum,au.Kunde FROM CRM_Aufgaben aa
LEFT JOIN ZUS_Therapie_Positionen pa ON pa.Id_Aktivitaet = aa.AufgabenNrCRM
LEFT JOIN PRO_Auftraege au ON au.AuftragNrPRO = aa.AuftragNrPRO
GROUP BY pa.Datum,au.Kunde
HAVING COUNT(*) > 1) SRC
ON SRC.Kunde = auf.Kunde
WHERE p.datum IS NOT NULL
GROUP BY p.Datum,a.AufgabenNrCRM,auf.Kunde
ORDER BY auf.Kunde,p.Datum

How to display the accurate sum when using 2 inner joins?

I am trying to get the results:
Quote = 12345
Total Assets = 14
Total Ordered = 22
When I run the queries separately I get the correct results, but when I put the two queries together my results are off (this is because the tables b and c do not represent each other)
my table summaries are as follows:
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
Result: 12345 : 14
Select a.Quote, SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN c on c.aId = a.Id
GROUP By a.Quote
Result: 12345 : 22
However, when I put them together:
Select a.Quote, SUM(b.Quantity)As 'Total Assets',SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = a.Id
INNER JOIN c on c.Aid = a.Id
GROUP BY a.Quote
Result 12345 : 56 : 308
I played with the group by but was never able to get the proper result. Any thoughts?
So far the solution I came up with is
With abc AS
(
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
)
SELECT abc.* , SUM(c.Quantity) As ' Total Ordered'
FROM abc
INNER JOIN c ON c.aid = a.Id
GROUP BY (all in abc)
It doesn't seem like the best way to get the results though..
Maybe use Left JOIN. The INNER JOIN will repeat rows of b and c. Also, try to see the result of:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = b.Id
INNER JOIN c on c.Aid = c.Id
GROUP BY a.Quote
And check if it's the right results that are computed. Then compare it against:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
LEFT JOIN b on b.Aid = b.Id
LEFT JOIN c on c.Aid = c.Id
GROUP BY a.Quote

SQL Counting # of times a member shows up with certain code values

I am running a query that returns the location of a member and the product the member is enrolled in. Each time a member makes a claim with their product, they get a revenue code associated to them. Below is my query that I have now:
SELECT DISTINCT
e.State,
f.Product,
d.MemberID,
b.RevenueCode
FROM
Claims a
INNER JOIN
dw.Revenue b
ON
a.RevenueKey = b.RevenueKey
INNER JOIN
dw.Member d
ON
a.MemberKey = d.MemberKey
INNER JOIN
dw.Product f
ON
a.ProductKey = f.ProductKey
INNER JOIN
dw.State
ON
a.StateKey = f.StateKey
WHERE
b.RevenueCode IN ('0134', '0135')
It returns a set like the following:
State Product MemberID RevenueCode
MN xxx 945-234-245 0134
MN xxx 945-234-245 0135
SD xxx 231-345-235 0134
When a MemberID has both 0134 and 0135 RevenueCodes associated with it, they are considered to be in a special category. How would I modify my above query to count the number of times a MemberID has both RevenueCodes by State and by Product?
SELECT DISTINCT
e.State
,f.Product
,d.MemberID
,b.RevenueCode
,(SELECT 1
FROM Claims AS a1
INNER JOIN dw.Revenue AS b1 ON a1.RevenueKey = b1.RevenueKey
WHERE b1.RevenueCode IN ('0134', '0135')
AND b.revenuekey = b1.revenuekey
AND a.MemberKey = a1.Memberkey
HAVING COUNT(DISTINCT b1.RevenueCode) = 2) AS SpecialCategory
FROM Claims a
INNER JOIN dw.Revenue b ON a.RevenueKey = b.RevenueKey
INNER JOIN dw.Member d ON a.MemberKey = d.MemberKey
INNER JOIN dw.Product f ON a.ProductKey = f.ProductKey
INNER JOIN dw.State ON a.StateKey = f.StateKey
WHERE b.RevenueCode IN ('0134', '0135')
SELECT DISTINCT
e.State,
f.Product,
d.MemberID,
b.RevenueCode.
CASE WHEN EXISTS(
SELECT NULL
FROM Claims a1
JOIN dw.Revenue b1 ON a1.RevenueKey = b1.RevenueKey
JOIN dw.Member d1 ON a1.MemberKey = d1.MemberKey
JOIN dw.Product f1 ON a1.ProductKey = f1.ProductKey
WHERE b1.RevenueCode IN('0134', '0135') AND
d1.MemberID = d.MemberID AND
f1.ProductKey = f.ProductKey AND
f1.StateKey = f.StateKey
) THEN 1 ELSE 0 END As IsSpecialCategory
FROM
...
Figured it out...Simply needed to Count the Distinct RevenueCodes and Group By State, Product, and MemberID