PIVOT from JOIN tables - sql

I have a large database and in this database, there are two tables I need to pull information from. I have pulled all the data I need out of the two tables by using both a JOIN and a CASE WHEN. Here is a screen shot from the output
SQL Server output
This is the code that I used to pull the data:
SELECT [PORTMultiMax].[dbo].cardholdertable.cardid as CardID,CardHolderTable.FirstName as FirstName,CardHolderTable.LastName as LastName, CardHolderTable.InitLet as MI, CardHolderPersonalDataXrTable.PersonalDataItem as Data,
CASE WHEN PersonalDataID = '4' THEN 'SSN'
WHEN PersonalDataID = '22' THEN 'Employer'
WHEN PersonalDataID = '30' THEN 'Training Type'
WHEN PersonalDataID = '32' THEN 'Primary Sponsor'
WHEN PersonalDataID = '37' THEN 'Training Date'
ELSE NULL END AS Description
FROM [PORTMultiMax].[dbo].[CardHolderTable]
join [PORTMultiMax].[dbo].[CardHolderPersonalDataXrTable]
on cardholdertable.CardID=CardHolderPersonalDataXrTable.CardID
where PersonalDataID IN (4,22,30,32,33,37)
order by LastName
The tables involved are named: CardHolderTable and CardHolderPersonalDataXrTable
What I need to do next is get rid of the duplicate name entries in the data. So for example, "JAMES AARON" has multiple rows due to him having multiple descriptors ("Training Date, TrainingType, Employer, and SSN").
I wanted to try and use a PIVOT to pull the row data out and put them in columns named "SSN, Employer, etc...". My problem is I have never used PIVOT before and I am confused on how to apply a PIVOT code to my current SQL query.
PLEASE HELP. Thank you so much

Given your query, I think conditional aggregation is simpler:
SELECT ch.FirstName, ch.LastName
MAX(CASE WHEN PersonalDataID = '4' THEN 1 ELSE 0 END) as is_SSN
MAX(CASE WHEN PersonalDataID = '22' THEN ELSE 0 END) as is_Employer,
MAX(CASE WHEN PersonalDataID = '30' THEN ELSE 0 END) as is_TrainingType,
MAX(CASE WHEN PersonalDataID = '32' THEN ELSE 0 END) as is_PrimarySponsor,
MAX(CASE WHEN PersonalDataID = '37' THEN ELSE 0 END) as is_TrainingDate
from [PORTMultiMax].[dbo].[CardHolderTable] ch join
[PORTMultiMax].[dbo].[CardHolderPersonalDataXrTable] cp
on ch.CardID = cp.CardID
where PersonalDataID IN (4, 22, 30, 32, 33, 37)
group by ch.FirstName, ch.LastName;

Related

How to present a particular SQL queried row as columns in output

I need to present the attached output in PIC1 as the result in PIC2. The query used for generating PIC1 output in SQLDeveloper:
select subs_nm, as_of_date, run_status, (select max (tp.pr_vl)
from ual_mng.tqueue tq, ual_mng.tparams tp, ual_mng.tstatus ts
WHERE tq.tid = tp.tid AND tq.tid = ts.tid and tq.run_id = pcm.run_id and tp.pr_nm in ('TOT_RECORD_CNT')) as RECORD_COUNT
from UAL_MNG.PCM_SUBS_RUN_DTL_VW pcm where SUBS_NM='S_TS2_AQUA_A1_RLAP_DL' and AS_OF_DATE in ('2021-09-01','2021-09-02') order by run_start_dtm desc;
Appreciate all help.
If you don't need it to be dynamic (ie. it will only be two columns and you know which two months they are) you can do
select subs_nm,
max(case when as_of_date = '2021-09-01' then RECORD_COUNT else 0 end) as SEP1,
max(case when as_of_date = '2021-09-02' then RECORD_COUNT else 0 end) as SEP2,
from (
-- Your query
)
group by subs_nm
You can work out the percentage difference using the same expressions.
nb. I would always use an explicit date format mask. This might not run on a different machine / software. So use to_date('2021-09-01', 'yyyy-mm-dd')
Posting the query, which worked in the script :
select subs_nm, SEP1, SEP2, round((((SEP1-SEP2)/SEP1)*100),2) as DIFF_PER from ( select subs_nm,
max(case when as_of_date='2021-09-01' then RECORD_COUNT else '0' end) as SEP1,
max(case when as_of_date='2021-09-02' then RECORD_COUNT else '0' end) as SEP2 from (-- *Main Query*);

Sql out put which come into multiple row converted to single row

This query give multiple row which needs to be shown in single row. Please help.
SELECT blng_serv_code, (COUNT (blng_serv_code)) AS total ,
DECODE (package_trx_yn, 'Y', 'PKG', 'N', 'NPKG') pkg_status FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC'
AND trx_date >= TO_DATE ('10/10/2019 00:00:00', 'MM/DD/YYYY HH24:MI:SS')AND blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code, package_trx_yn
If you want the value in a single row, leave out the package status:
SELECT blng_serv_code, COUNT(*) AS total
FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC' AND
trx_date >= DATE '2019-10-10' AND
blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code;
If you do want the package status, then you need to explain the logic for including it "on a single row".
EDIT:
It sounds like you want the values in separate columns:
SELECT blng_serv_code, COUNT(*) AS total,
SUM(CASE WHEN package_trx_yn = 'Y' THEN 1 ELSE 0 END) as pkg_cnt,
SUM(CASE WHEN package_trx_yn = 'N' THEN 1 ELSE 0 END) as npkg_cnt
FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC' AND
trx_date >= DATE '2019-10-10' AND
blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code;

How do I change a constant value to a column header in SQL?

The SQL query:
select type,count(*), 'Active'
from file where removed = '0'
union all
select type,count(*), 'Removed'
from file where removed = '1'
gives:
TYPE COUNT ( * ) Constant value
A 24,168 Active
A 1 Removed
B 8,280 Active
B 1,263 Removed
However, how can I change the SQL to get:
TYPE Active Removed
A 24,168 1
B 8,280 1,263
Supplementary optional question: and what's the best way to include the following total?
TYPE Active Removed
A 24,168 1
B 8,280 1,263
Total 32,448 1,264
This is my best answer to the supplementary, please let me know if you see any flaws or improvements:
select
type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Group by type
union all
select 'Total',
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Thank you to everyone who commented or answered, your help is appreciated.
You can try:
select
type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Group by type
Use case expressions to do conditional aggregation:
select type,
count(case when removed = '0' then 1 end) as "Active",
count(case when removed = '1' then 1 end) as "Removed"
from file
group by type
If there are many rows with other removed values than 0/1, and the column is indexed, you can throw in a
WHERE removed IN ('0','1')
to speed things up!
In order to get totals into the answer without union try:
select
coalesce(type, 'Totals') type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) Active,
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) Removed
from file
Group by rollup(type)
This works for v6.1 and later.

Trying to group several rows based on donatedmoney status

I'm really struggling with this. I just can't seem to figure it out. I've got the concept in my head but don't exactly know how to put my plain language understanding of how to solve the problem into the correct Syntax.
Here is the question.
Give me a list of all donors and their addresses categorized by whether they donated art, money, or both.
Here is the set up for the tables.
CareTakers: CareTakerID, CareTakerName
Donations: DonationID, DonorID, DonatedMoney, ArtName, ArtType, ArtAppraisedPrice, ArtLocationBuilding, ArtLocationRoom, CareTakerID
Donors: DonorID, DonorName, DonorAddress
Here is what I have for my code so far.
SELECT
DISTINCT(DonorName), DonorAddress
FROM
Donors JOIN Donations ON Donors.DonorID = Donations.DonorID
GROUP BY
DonatedMoney
HAVING
DonatedMoney = 'Y' OR DonatedMoney = 'N' OR DonatedMoney = 'Y' AND ArtName IS NOT NULL
Any help would be highly appreciated!
Why would you use a having clause? The question specifies no filtering. The following summarizes the donations to get what you need and then joins the results back to the donors table:
select d.*, don.DonationType
from donors d join
(select don.donorid,
(case when sum(case when donatedmoney = 'Y' then 1 else 0 end) > 0 and
sum(case when artname is not null then 1 else 0 end) > 0
then 'Both'
when sum(case when donatedmoney = 'Y' then 1 else 0 end) > 0
then 'Money'
when sum(case when artname is not null then 1 else 0 end)
then 'Art'
else 'Neither'
end) as DonationType
from donations don
group by don.donorid
) don
on d.donorid = don.donorid

Merging data SQL Query

I have a query request where I have to show one customer activity for each web-site but it has to be only one row each, instead of one customer showing multiple times for each activity.
Following is the query I tried but brings lot more rows. please help me as how I can avoid duplicates and show only one customer by each row for each activity.
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
Sounds like you need to group by customer_id and perform aggregations for the other columns you are selecting. For example:
sum(case when s.subscription_type = '5' then 1 else 0 end) as pb_subs_count
You could try one of two things:
Use a GROUP BY statement to combine all records with the same id, e.g.,
...
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id
Use the DISTINCT command in your SELECT, e.g.,
SELECT DISTINCT i.customer_id, i.SEGMENT, ...
you could use a aggregation (SUM) on customer_id, but what do you expect to happen on the other fields? for example, if you have SUBSCRIPTION_TYPE 5 and 13 for the same customer (2 rows), which value do you want?
Perhaps you are looking for something like this:
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
MAX(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
MAX(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
MAX(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id, i.SEGMENT
I can't be sure, though, without knowing more about the tables involved.