SQL Query to Combine rows - sql

I have a query that currently prints out what I need but doesn't combine the rows that I need. For example, I need the first two rows with the meter name to be combined together and so on for the rest of the meter names.
This is currently what I have:
SELECT
--Displays Client Number
CASE
WHEN v.MID IS NULL THEN ''
ELSE v.ClientNumber
END AS 'Client Number',
--Displays MID Number
CASE
WHEN v.MID IS NULL THEN ''
ELSE v.MID
END AS MID,
--Displays Meter Name
CASE
WHEN v.MID IS NULL THEN ''
ELSE v.MeterName
END AS 'Meter Name',
/*
CASE
WHEN v.MID IS NULL THEN 0
ELSE SUM(v.MCF)
END AS MCF,
*/
--Displays January's MCF
CASE
WHEN v.AccountPeriod = '2018-01-01' THEN SUM(v.MCF)
ELSE 0
END AS January,
--Displays Febuary's MCF
CASE
WHEN v.AccountPeriod = '2018-02-01' THEN SUM(v.MCF)
ELSE 0
END AS Febuary,
CASE
WHEN v.MID IS NULL THEN 0
ELSE SUM(v.mcf)
END AS 'Meter Total'
FROM Volumes v
LEFT JOIN CurrentMeters cm
ON v.MID = cm.MID
WHERE cm.ClientNumber = 107500
GROUP BY v.MID, v.AccountPeriod, v.ClientNumber, v
Does anyone have any suggestions as to what I should do or how I should approach this?

I think you just want conditional aggregation:
SELECT (CASE WHEN v.MID IS NULL THEN '' ELSE v.ClientNumber END) AS Client_Number,
COALESCE(WHEN v.MID, '') as MID,
(CASE WHEN v.MID IS NULL THEN '' ELSE v.MeterName END) AS Meter_Name,
SUM((CASE WHEN v.MID IS NULL THEN 0 v.MCF END) AS MCF,
SUM(CASE WHEN v.AccountPeriod = '2018-01-01' THEN v.MCF ELSE 0 END) AS January,
SUM(CASE WHEN v.AccountPeriod = '2018-02-01' THEN v.MCF ELSE 0 END) AS January,
SUM(CASE WHEN v.MID IS NULL THEN 0 ELSE v.mcf END) AS Meter_Total
FROM Volumes v JOIN
CurrentMeters cm
ON v.MID = cm.MID
WHERE cm.ClientNumber = 107500
GROUP BY (CASE WHEN v.MID IS NULL THEN '' ELSE v.ClientNumber END),
COALESCE(WHEN v.MID, ''),
(CASE WHEN v.MID IS NULL THEN '' ELSE v.MeterName END);
Notes:
Your WHERE clause is turning the outer join into an inner join, so there is no reason to express an outer join.
The GROUP BY keys specify what defines a row in the result set. Each combination of unique values in the data is in exactly one row. Hence, you don't want AccountPeriod in the GROUP BY.
Presumably, you want one row for each of the expressions that define a row, so these expressions are in the group by.
For conditional aggregation, the CASE expression is an argument to an aggregation function such as SUM().

Related

Case Statement having no effect on output

I am trying to get sums of donations based on the bank approval status and grouped by gift kind. However, it the script outputs RR and NR donations on separate lines (see below the script). It seems like the case statements aren't working at all.
select gift_kind,
case
when c.bank_approval_status = 'AP' then
sum(c.charge_amount) end approved,
case
when c.bank_approval_status in ('RR','NR') then
sum(c.charge_amount) end rejected,
case
when c.bank_approval_status = 'AR' then
sum(c.charge_amount)*-1 end refunded,
case
when c.bank_approval_status not in ('AR','AP','RR','NR') then
sum(c.charge_amount) end other_status
from charge_log c, transactions t
where c.account_id=t.account_id
and c.process_id= 'CHG - 02532'
and c.gift_date=t.gift_date
and c.gift_seq=t.gift_seq
and C.PLEDGE_NUMBER=t.pledge_number
and t.sts='A'
group by t.fund_type, t.gift_kind, c.bank_approval_status
order by gift_kind asc
I believe you are looking for this logic:
select gift_kind,
sum(case when c.bank_approval_status = 'AP' then c.charge_amount
end) as approved,
sum(case when c.bank_approval_status in ('RR', 'NR') then c.charge_amount
end) as rejected,
sum(case when c.bank_approval_status in ('AR') then c.charge_amount*-1
end) as refunded,
sum(case when c.bank_approval_status not in ('AR','AP','RR','NR') then c.charge_amount
end) other_status
from charge_log c join
transactions t
on c.account_id = t.account_id and
c.gift_date = t.gift_date and
c.gift_seq = t.gift_seq and
C.PLEDGE_NUMBER = t.pledge_number
where c.process_id = 'CHG - 02532' and t.sts = 'A'
group by t.fund_type, t.gift_kind
order by gift_kind asc
Notes:
Learn to use proper JOIN syntax. Never use commas in the FROM clause.
The JOIN conditions should all be in the ON clause, not the WHERE clause.
The CASE is an argument to the SUM().
Remove the bank_approval_status from the GROUP BY.
I don't know why fund_type is in the GROUP BY. You may have a reason for that so I left it.
You need to put the case clauses inside the sums, and add else 0 to make sure you don't get null as a result:
sum(case
when c.bank_approval_status = 'AP' then
c.charge_amount else 0 end) approved,
sum(case
when c.bank_approval_status in ('RR','NR') then
c.charge_amount else 0 end) rejected,
sum(case
when c.bank_approval_status = 'AR' then
-c.charge_amount else 0 end) refunded,
sum(case
when c.bank_approval_status not in ('AR','AP','RR','NR') then
c.charge_amount else 0 end) other_status
And your group by should rarely be on columns you use in aggregations (here bank_approval_status in the sum). Change to:
group by gift_kind
Depending on your scheme, other fields might need to be added to the group by clause but then it would make sense to also put them in the select and order by clauses.

Update a complex SQL query to add a new column with the sum of two columns

The below SQL query creates a table with n number of columns named in the next line.
...., curr_amount, tax_amount, ....
I am having a very tough time updating the below query to create a new column called total and position it exactly after tax_amount column and the total column should contain the values that are obtained after sum of curr_amount & tax_amount.
I have been working on this from more than one day but couldn't figure it out.
P.S. Still a noob here. Thanks alot for your time.
.
SELECT Isnull(t.total_month, 'Total') total_month,
t.tax_amount,
t.curr_amount,
t.usage_qty,
t.kh_qty,
t.bill_cnt
FROM (SELECT dbo.Sigmadf(bm.posted_date, 'YYYY-MM') total_month,
Sum(CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END) usage_qty,
Sum(CASE
WHEN bm.curr_amount IS NULL THEN 0
ELSE bm.curr_amount
END) curr_amount,
Sum(CASE
WHEN bm.adj_amount IS NULL THEN 0
ELSE bm.adj_amount
END) adj_amount,
Sum(CASE
WHEN bm.bal_fwd_amount IS NULL THEN 0
ELSE bm.bal_fwd_amount
END) bal_forward,
Sum(CASE
WHEN bm.tax_amount IS NULL THEN 0
ELSE bm.tax_amount
END) tax_amount,
Sum(CASE
WHEN bm.due_amount IS NULL THEN 0
ELSE bm.due_amount
END) due_amount,
Sum(CASE
WHEN bm.last_total_paid_amount IS NULL THEN 0
ELSE bm.last_total_paid_amount * -1
END) paid_amount,
Sum(CASE
WHEN bm.bill_print = 'Y' THEN 1
ELSE 0
END) pdf_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '0' THEN 1
ELSE 0
END) reg_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '1' THEN 1
ELSE 0
END) ftime_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '9999' THEN 1
ELSE 0
END) ltime_cnt,
Count(*) bill_cnt,
Sum(CASE
WHEN bill_status = '01' THEN 1
ELSE 0
END) canc_cnt,
Sum(CASE
WHEN bill_status = '01' THEN
CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END
ELSE 0
END) canc_usg,
Sum(CASE
WHEN vis.kh_qty IS NULL THEN 0
ELSE Cast(vis.kh_qty AS NUMERIC(18, 2))
END) kh_qty
FROM bill_master bm WITH (nolock)
INNER JOIN (SELECT bill_no,
Sum(CASE
WHEN vpb.recurr_charge_type IN ( 'T4',
'SLF' )
THEN
CASE
WHEN vpb.print_qty = 'Y'
AND vpb.usage_qty IS NOT NULL
THEN
Cast (vpb.usage_qty AS
NUMERIC(18, 2))
ELSE 0
END
ELSE 0
END) usage_qty
FROM v_print_bills_all vpb
GROUP BY bill_no) rr
ON rr.bill_no = bm.bill_no
LEFT OUTER JOIN vis_bill_master_cr vis WITH (nolock)
ON bm.bill_no = vis.bill_no
WHERE 1 = 1
AND dbo.Trunc(bm.posted_date) >= '20150101'
AND dbo.Trunc(bm.posted_date) <= '20151124'
AND bm.posted_date IS NOT NULL
AND bm.cust_id NOT IN (SELECT cc.code_type cust_id
FROM code_table cc WITH (nolock)
WHERE cc.code_tabname = 'RptExclCust'
AND cc.code_value = 'cust_id')
GROUP BY dbo.Sigmadf(bm.posted_date, 'YYYY-MM') WITH rollup)t
I must say that the explanation is not so clear.
From my understanding, you want the total of two columns.
So, wrap all your query between parenthesis, call it subQuery, and make the sum of the two columns on top:
SELECT subQuery.total_month as bill_date,
subQuery.curr_amount as amount,
subQuery.tax_amount tax,
subQuery.curr_amount + subQuery.tax_amount as [total],
...
FROM
(..your entire query here..) as subQuery

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

Avoiding a divide by zero error in a case statement

I am getting a divide by zero error in my script.
Can anyone please help.
I am trying to divide two records and one of them has zero in it. I dont want to lose the row, please advise.
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) as "Paid in 24hrs",
COUNT([MONTH_OF_SUSPENSION])/sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) as "Achieved"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
You can introduce a second case to check the result of the sum:
case
when sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) > 0
then COUNT([MONTH_OF_SUSPENSION])/sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end)
else 0 /* a default value that makes sense to you */
end as "Achieved"
Looking at your code I could assume you are using MSSQL and therefore you could use nullif which returns null if two arguments are equal. So for example your code could look like :
COUNT([MONTH_OF_SUSPENSION])/nullif(sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end),0) as "Achieved"
What it does is if the value of the sum operator is equal 0 then the divisor is turn from zero into null and that will result in the entire equation to become null.
use another case statement to check the result of your sum
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "Paid in 24hrs",
case
when sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) = 0 then 'whatever you want in this case'
else COUNT([MONTH_OF_SUSPENSION])/sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "Achieved"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
although this is pretty nasty looking, so you could tidy it up a bit with a sub-select:
select
year,
month,
request,
PaidIn24hrs,
case
when PaidIn24hrs = 0 then 'whatever you want in this case'
else request/PaidIn24hrs
end as "Achieved"
from
(
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "PaidIn24hrs"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
)

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.