I have a table billing_history which consists of the following fields
CREATE TABLE [dbo].[BILLING_HISTORY2](
[ID] [int] IDENTITY(1,1) NOT NULL,
[READING_MONTH_YEAR] [date] NULL,
[READING] [int] NULL,
[CONSUMER_ID] [int] NULL,
[payment_status] [bit] NOT NULL
)
http://www.sqlfiddle.com/#!3/892e0/5
The following queries return the MAX Paid And Max Unpaid Values for a Consumer
SELECT MAX(READING) AS 'MAXIMUM_PAID_READING',consumer_id from billing_history2
where payment_status=0 GROUP BY consumer_id;
SELECT MAX(READING) AS 'MAXIMUM_UNPAID_READING',consumer_id from billing_history2
where payment_status=1 GROUP BY consumer_id;
However when i join them to subtract the MAXIMUM_PAID_READING from MAXIMUM_UNPAID_READING to get the current reading, by joining the above two queries, it results in returning all those records which have a matched consumer_id. So if a consumer hasn't paid any bill yet, the id would be omitted in the PAID_READING and hence an INNER JOIN doesn't return any result. IF i use FULL OUTER JOIN, it return all the records but sets the difference to NULL.
I need to find out the current USAGE of the customer by subtracting it from the previous unpaid USAGE.
How do i go about joining these two queries in such a way that the resulting difference is found irrespective whether the person has paid a bill in the past or not.
Don't join them.
SELECT
MAX(CASE WHEN payment_status=0 THEN READING ELSE NULL END) AS 'MAXIMUM_PAID_READING',
MAX(CASE WHEN payment_status=1 THEN READING ELSE NULL END) AS 'MAXIMUM_UNPAID_READING',
MAX(CASE WHEN payment_status=0 THEN READING ELSE NULL END)
- MAX(CASE WHEN payment_status=1 THEN READING ELSE NULL END)
AS 'DIFF_READING',
consumer_id from billing_history2
GROUP BY consumer_id;
If you want handle NULL values from MAX function, use ISNULL function:
SELECT
ISNULL(MAX(CASE WHEN payment_status=0 THEN READING ELSE NULL END),0) AS 'MAXIMUM_PAID_READING',
ISNULL(MAX(CASE WHEN payment_status=1 THEN READING ELSE NULL END),0) AS 'MAXIMUM_UNPAID_READING',
ISNULL(MAX(CASE WHEN payment_status=0 THEN READING ELSE NULL END),0)
- ISNULL(MAX(CASE WHEN payment_status=1 THEN READING ELSE NULL END),0)
AS 'DIFF_READING',
consumer_id from billing_history2
GROUP BY consumer_id;
It's ok to use left outer join, but use isnull on your max value.
ex:
max(...) - isnull(max(...),0) as ...
In your case is necessary to use CASE expression
SELECT CONSUMER_ID,
MAX(CASE WHEN payment_status = 0 THEN READING ELSE 0 END) AS 'MAXIMUM_PAID_READING',
MAX(CASE WHEN payment_status = 1 THEN READING ELSE 0 END) AS 'MAXIMUM_UNPAID_READING',
MAX(CASE WHEN payment_status = 0 THEN READING ELSE 0 END) -
MAX(CASE WHEN payment_status = 1 THEN READING ELSE 0 END) AS diff
FROM billing_history2
GROUP BY consumer_id
Demo on SQLFiddle
Related
I have a table in SQL Server called ShippingDocSummary which contains all historical records for shipping documents. For a given document number, there can be any number of historical records/transactions. What I am trying to do is create a view that summarizes that table and calculates various column values. My issue comes when trying to get a specific value from the source table based on a calculated column value from the same source table.
Here is a simplified example of what the source table looks like:
DocNum DocHistID StatusCode StatusQty StatusDate
12345 10000001 AS1 2 2/16/2020
12345 10000002 D6T 2 4/20/2020
12345 10000003 COR 2 4/20/2020
12345 10000004 AS1 2 5/5/2020
My code to create my summary so far is as follows:
SELECT
DocNum,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'AS_' THEN StatusQty ELSE 0 END) AS AS_QTY,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'D6T' THEN StatusQty ELSE 0 END) AS D6T_QTY,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'COR' THEN StatusQty ELSE 0 END) AS COR_QTY,
MAX(CASE WHEN ShippingDocSummary.StatusCode LIKE 'AS_' THEN DocHistID ELSE null END) AS LastAS_DHID
FROM ShippingDocSummary
GROUP BY DocNum
This gives me the following, which is correct:
DocNum AS_QTY D6T_QTY COR_QTY LastAS_DHID
12345 4 2 2 10000004
What I am trying to get next, as a column, is the StatusDate that correlates to the LastAS_DHID value that was calculated from the select (i.e. I need the next column to show '5/5/2020' since that date ties to the DocHistID '10000004').
In Power Bi, I'd use a lookupvalue function, but as I transfer my logic to the SQL server, I think I need to use a derived CASE WHEN type of query, but unsure of how to structure the syntax. Any help is greatly appreciated!
Maybe you have to create your on table and then do a left join. This being said, Try this:
SELECT A.DocNum,
A.AS_QTY,
A.D6T_QTY,
A.COR_QTY,
A.LastAS_DHID,
B.StatusDate
FROM (
SELECT DocNum,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'AS_' THEN StatusQty ELSE 0 END) AS AS_QTY,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'D6T' THEN StatusQty ELSE 0 END) AS D6T_QTY,
SUM(CASE WHEN ShippingDocSummary.StatusCode LIKE 'COR' THEN StatusQty ELSE 0 END) AS COR_QTY,
MAX(CASE WHEN ShippingDocSummary.StatusCode LIKE 'AS_' THEN DocHistID ELSE null END) AS LastAS_DHID
FROM ShippingDocSummary
GROUP BY DocNum) A
LEFT JOIN TABLE_WITH_DOCHIST_10000004 B
ON A.LastAS_DHID = B.DocHistID
SELECT DISTINCT
DocNum,
SUM(CASE WHEN StatusCode LIKE 'AS_' THEN StatusQty ELSE 0 END) OVER (PARTITION BY DocNum) AS AS_QTY,
SUM(CASE WHEN StatusCode LIKE 'D6T' THEN StatusQty ELSE 0 END) OVER (PARTITION BY DocNum) AS D6T_QTY,
SUM(CASE WHEN StatusCode LIKE 'COR' THEN StatusQty ELSE 0 END) OVER (PARTITION BY DocNum) AS COR_QTY,
FIRST_VALUE(StatusDate) OVER (PARTITION BY DocNum ORDER BY CASE WHEN StatusCode LIKE 'AS_' THEN DocHistID ELSE null END DESC) AS LastAS_DHID
FROM ShippingDocSummary
I've converted your aggregate functions to windowed versions with partitioning on the original grouping column. The select distinct is then necessary to actually collapse the rows to a single aggregated row. If first_value() isn't available on your platform there are other alternatives.
Here's one that worked for me as a scalar subquery:
(
SELECT StatusDate FROM ShippingDocSummary sds2
WHERE sds2.DocHistId =
MAX(
CASE WHEN ShippingDocSummary.StatusCode LIKE 'AS_'
THEN ShippingDocSummary.DocHistID ELSE null END
)
) AS LastAS_DHID
I'm writing a pretty long report, which runs without error, but even though I'm using 'select distinct' it's still showing 11 rows for each unique value i'm trying to report on.
The unique value that I need to display only 1 row per each distinct occurrence is case number, or 'cases.casenum'.
I've included a screenshot of the output which gives a pretty clear idea of what I'm going for... here's the code:
SELECT distinct
(
SELECT count(distinct cases.casenum)
FROM (cases INNER JOIN user_case_data ON cases.casenum=user_case_data.casenum)
WHERE (user_case_data.discharged_date >= '##START##'
AND user_case_data.discharged_date <= '##END##')
)
AS "Total Lost Files", cases.casenum AS "Case Number", user_case_data.discharged_date AS "Discharged Date",
(case when case_notes.topic like 'LOS Case Status Update' THEN case_notes.note_date else null end)
AS "Gendoc #31 Mailed",
(case when case_checklist.code='101' then case_checklist.due_date else null end)
AS "Advised Attorney",
(case when case_notes.topic like 'LOS Updated Lein Ltr' THEN case_notes.note_date else null end)
AS "Sent Updated Lien Ltr",
(case when case_checklist.code='109' then case_checklist.due_date else null end)
AS "Time Allocation Completed",
(case when case_checklist.code='110' then case_checklist.due_date else null end)
AS "Attorney Signed Affidavit",
(case when case_checklist.code='111' then case_checklist.due_date else null end)
AS "Lien Letters Sent",
(case when case_checklist.code='112' then case_checklist.due_date else null end)
AS "Sent Lien to Counsel",
(case when case_checklist.code='113' then case_checklist.due_date else null end)
AS "Received Costs and Transferred"
FROM (cases LEFT JOIN case_checklist ON cases.casenum=case_checklist.case_id
LEFT JOIN user_case_data ON case_checklist.case_id=user_case_data.casenum
LEFT JOIN case_notes ON user_case_data.casenum=case_notes.case_num)
WHERE (user_case_data.discharged_date >= '##START##'
AND user_case_data.discharged_date <= '##END##')
ORDER BY user_case_data.discharged_date ASC;
Additional info:
-Each case number only has 1 discharge date. So for each row, there should be only 1 case number and 1 discharge date.
-There can be many records that exist per case number on the case_notes and case_checklist tables, however I'm only trying to pull the date for 1 single note (with topic specified in case statement), and 1 single checklist item (again specified in case statement)
-The first column isn't really necessary and there's no reason why I want to count the total number of cases for each row... I just wanted a total count somewhere in the output and didn't know how else I could do it.
As suggested by JustinStolle, he was correct in his suggestion for aggregate functions and a GROUP BY:
SELECT
(
SELECT count(distinct cases.casenum)
FROM (cases INNER JOIN user_case_data ON cases.casenum=user_case_data.casenum)
WHERE (user_case_data.discharged_date >= '##START##'
AND user_case_data.discharged_date <= '##END##')
)
AS "Total Lost Files", cases.casenum AS "Case Number", user_case_data.discharged_date AS "Discharged Date",
MAX(case when case_notes.topic like 'LOS Case Status Update' THEN case_notes.note_date else null end)
AS GENDOC_31_Mailed,
MAX(case when case_checklist.code='101' then case_checklist.due_date else null end)
AS ADVISED_ATTORNEY,
MAX(case when case_notes.topic like 'LOS Updated Lein Ltr' THEN case_notes.note_date else null end)
AS "Sent Updated Lien Ltr",
MAX(case when case_checklist.code='109' then case_checklist.due_date else null end)
AS "Time Allocation Completed",
MAX(case when case_checklist.code='110' then case_checklist.due_date else null end)
AS "Attorney Signed Affidavit",
MAX(case when case_checklist.code='111' then case_checklist.due_date else null end)
AS "Lien Letters Sent",
MAX(case when case_checklist.code='112' then case_checklist.due_date else null end)
AS "Sent Lien to Counsel",
MAX(case when case_checklist.code='113' then case_checklist.due_date else null end)
AS "Received Costs and Transferred"
FROM cases
LEFT JOIN case_checklist ON cases.casenum = case_checklist.case_id
LEFT JOIN user_case_data ON case_checklist.case_id=user_case_data.casenum
LEFT JOIN case_notes ON user_case_data.casenum=case_notes.case_num AND case_notes.topic LIKE 'LOS Case Status Update'
WHERE (user_case_data.discharged_date >= '##START##'
AND user_case_data.discharged_date <= '##END##')
GROUP BY cases.casenum, user_case_data.discharged_date
ORDER BY user_case_data.discharged_date ASC;
I am getting an error -
can not nest aggregate operations when trying to run the below part of the query in Teradata.
When SeqCount = 2 and surgery data is the same as the first surgery, I want the 2nd surgery date (SecondSurgery) to be null else return the 2nd surgery data.
Any help would be greatly appreciated.
SELECT
pat_id,
PatientMRN,
PatientName,
AdmitDate,
DischargeDate,
MIN(case when SeqCount=1 then ORProcName else null end) as FirstProcedure,
MIN(case when SeqCount=1 then SurgeryDate else null end) as FirstSurgery,
MIN(case when SeqCount=2 then ORProcName else null end) as SecondProcedure,
MIN(case when SeqCount=2 and SurgeryDate = FirstSurgery then NULL else SurgeryDate end) as SecondSurgery
as the ErrorMsg is saying it's not possible due to the SET-based processing (all at once). - You can force an sequential processing with sub-queries and calculate SecondSurgery in the outer-SQL.
This question already has an answer here:
How to use an Alias in a Calculation for Another Field
(1 answer)
Closed 4 years ago.
select
category, count(category) as 'TotalCounts',
COUNT(case kind when 'avail'then 1 else null end) as 'avail',
Count(case kind when 'offers' then 1 else null end) as 'offers',
COUNT(CASE contactMethod WHEN 'SMS' then 1 else null END) as 'SMS',
COUNT(case contactMethod when 'call' then 1 else null end) as 'call',
CONVERT(varchar(254),COUNT (case when max_biz_status='A' OR
max_biz_status ='B' then 1 else null end) * 100 / count(category)) +'%'
as 'Percetange'
from reports
group by category
order by TotalCounts
Instead of calculating again in Convert method i want to use avail* 100 / TotalCounts like i did in order by when i used TotalCounts.
i tried:
CONVERT(varchar(254),avail * 100 / TotalCounts) +'%' as 'Percetange'
but i get 'invalid column name' for avail and TotalCounts
You can't do that because your TotalCounts column is made from your result set.
you can try to use a subquery to contain it then calculation.
if your mssql version support CONCAT function you can use it let the SQL clearer.
SELECT t1.*,CONCAT((max_biz_statusCnt * 100 /TotalCounts),'%')as 'Percetange'
FROM
(
select
category,
count(*) as 'TotalCounts',
COUNT(case kind when 'avail'then 1 else null end) as 'avail',
Count(case kind when 'offers' then 1 else null end) as 'offers',
COUNT(CASE contactMethod WHEN 'SMS' then 1 else null END) as 'SMS',
COUNT(case contactMethod when 'call' then 1 else null end) as 'call',
COUNT (case when max_biz_status='A' OR max_biz_status ='B' then 1 else null end) 'max_biz_statusCnt'
from reports
group by category
) t1
order by TotalCounts
You can't use avail or TotalCounts as you just created them, so they aren't in scope, using a common-table expression is one way to fix this:
WITH cte AS (
SELECT
category,
COUNT(category) AS TotalCounts,
COUNT(case kind WHEN 'avail' THEN 1 ELSE NULL END) AS avail,
COUNT(case kind WHEN 'offers' THEN 1 ELSE NULL END) AS offers,
COUNT(CASE contactMethod WHEN 'SMS' THEN 1 ELSE NULL END) AS SMS,
COUNT(case contactMethod WHEN 'call' THEN 1 ELSE NULL END) AS [call]
FROM
reports
GROUP BY
category)
SELECT
*,
CONVERT(varchar(254),avail * 100 / TotalCounts) +'%' AS Percetange --(sic)
FROM
cte
ORDER BY
TotalCounts;
I have a SQL database with people, from which I want to see how much experience each person has in a specific department.
In the current query I have the following code:
SELECT [PERSON_ID]
,sum(case when [DEPARTMENT] = 'Marketing' then 1 else 0 end) as Exp_Marketing
,sum(case when [FUNCTION_DESC] = 'Finance' then 1 else 0 end) as Exp_Finance
FROM [xxxx].[xxxx].[xxxx]
GROUP BY [PERSON_ID]
Each person has one row for the months of service, so a person with 12 months of experience in Finance has a value of 12 in the Exp_Finance column.
The issue however is that the result now shows the outcome for all people. Also the one who already left the organization. How can I make sure the result only shows the historical information for the people currently part in the organization. In other words, the ones actually having a row with "2018M06" as value for the Date column.
You can use a having clause:
SELECT [PERSON_ID],
sum(case when [DEPARTMENT] = 'Marketing' then 1 else 0 end) as Exp_Marketing,
sum(case when [FUNCTION_DESC] = 'Finance' then 1 else 0 end) as Exp_Finance
FROM [xxxx].[xxxx].[xxxx]
GROUP BY [PERSON_ID]
HAVING MAX([DATE]) = '2018M06';
Your month format seems amenable to using MAX().
You should add an EXISTS within a WHERE clause so you only include people meeting your criteria.
SELECT [PERSON_ID]
,sum(case when [DEPARTMENT] = 'Marketing' then 1 else 0 end) as Exp_Marketing
,sum(case when [FUNCTION_DESC] = 'Finance' then 1 else 0 end) as Exp_Finance
FROM [xxxx].[xxxx].[xxxx] A
WHERE EXISTS (SELECT * FROM [xxxx].[xxxx].[xxxx] B
WHERE A.PERSON_ID = B.PERSON_ID AND B.[DATE] = '2018M06')
GROUP BY [PERSON_ID]