Retrieve different customer status - sql

I want to write a query to retrieve the result from the table.
When the name all my statuses are completed to show me completed. When the status has completed but there is another status such as in progress or created then show only the other status
CustomName
STATUS
order
Ivan Ivanov
completed
1
Stoqn Stoqnov
completed
1
Dimityr Ivanov
completed
1
Ivan Ivanov
completed
2
Dimityr Ivanov
completed
2
Ivan Ivanov
inprocess
2
Stoqn Stoqnov
completed
2
Dimityr Ivanov
completed
3
Dimityr Ivanov
created
4
Stoqn Stoqnov
completed
3
Ivan Ivanov
completed
4
Stoqn Stoqnov
completed
4
Expected result
Ivan Ivanov
inprocess
Dimityr Ivanov
created
Stoqn Stoqnov
completed
Query:
SELECT distinct CustomName,
(CASE WHEN [STATUS] ='COMPLETED' THEN 'completed'
WHEN [STATUS] ='inprocess' THEN 'inprocess'
WHEN [STATUS] ='created' THEN 'created' END ) AS [STATUS]
from [dbo].[Customers]

You can do something like the following where you count how many of each status there are per customer and then choose in a priority order which to display.
declare #Test table (CustomName varchar(32), [STATUS] varchar(32), [Order] int)
insert into #Test (CustomName, [STATUS], [Order])
values
('Ivan Ivanov', 'completed', 1),
('Stoqn Stoqnov', 'completed', 1),
('Dimityr Ivanov', 'completed', 1),
('Ivan Ivanov', 'completed', 2),
('Dimityr Ivanov', 'completed', 2),
('Ivan Ivanov', 'inprocess', 2),
('Stoqn Stoqnov', 'completed', 2),
('Dimityr Ivanov', 'completed', 3),
('Dimityr Ivanov', 'created', 4),
('Stoqn Stoqnov', 'completed', 3),
('Ivan Ivanov', 'completed', 4),
('Stoqn Stoqnov', 'completed', 4);
with cte as (
select CustomName
, sum(case when [status] = 'completed' then 1 else 0 end) over (partition by CustomName) Completed
, sum(case when [status] = 'created' then 1 else 0 end) over (partition by CustomName) Created
, sum(case when [status] = 'inprocess' then 1 else 0 end) over (partition by CustomName) InProcess
from #Test
)
select CustomName
-- This logic could be more complex if desired
, case when InProcess > 0 then 'In Process' when Created > 0 then 'Created' else 'Completed' end
from cte
group by CustomName, Completed, Created, InProcess;
Returns:
CustomName
Status
Dimityr Ivanov
Created
Ivan Ivanov
In Process
Stoqn Stoqnov
Completed
Note: Providing the DDL+DML as I have shown, makes it much easier for people to assist.

I don't think this needs window functions or cross joins, just a simple GROUP BY with conditional counts
SELECT
CustomName,
CASE WHEN COUNT(CASE WHEN [status] = 'created' THEN 1 END) > 0 THEN 'Created'
WHEN COUNT(CASE WHEN [status] = 'inprocess' THEN 1 END) > 0 THEN 'In Process'
ELSE 'Completed' END
FROM YourTable t
GROUP BY t.CustomName;

Try the following:
The idea is to use cte to find all Customer Name who contain different type of status
and then use UNION ALL to find all Customer Name who ONLY contains "Completed" status
;WITH cte AS (
SELECT DISTINCT CustomName, [STATUS]
FROM [dbo].[Customers]
WHERE [STATUS] <> 'Completed'
)
SELECT *
FROM cte
UNION ALL
SELECT DISTINCT CustomName, [STATUS]
FROM [dbo].[Customers]
WHERE CustomName NOT IN (SELECT CustomName FROM cte)

Related

Conditional count when case = 1, DB2

I'm currently trying to figure out the best way to do a conditional count as an alias in DB2 for Iseries. The below values represent job statuses where a job can be created, completed and cancelled so any one job will possibly have multiple status codes attached to it.
However, for my final value, I'm trying to get a count of jobs that only have the created status so that I can show how many are still open jobs. Basically looking for cases where the count for the created case = 1, but the below fails at the '='
SELECT
COUNT(CASE A1.JOB WHEN = 'CREATED' THEN 1 END) AS CREATED,
COUNT(CASE A1.JOB WHEN = 'CANCELLED' THEN 1 END) AS CANCELLED,
COUNT(CASE WHEN A1.JOB 'CREATED' = 1 then 1 END) AS OPEN
FROM SCHEMA.TABLE A1;
sample data and results:
Job ID | Status_code
-------------------------
123 'CREATED'
123 'COMPLETED'
521 'CREATED'
521 'CANCELLED'
645 'CREATED'
Results:
JOB | CREATED | CANCELLED | OPEN
-------------------------------------------
123 1 0 0
521 1 1 0
645 1 0 1
Assuming that the only "close" status is 'CANCELLED', you can use not exists like this:
select count(*)
from schema.table t
where t.status_code = 'CREATED' and
not exists (select 1
from schema.table t2
where t2.job = t.job and
t2.status_code in ('CANCELLED', 'COMPLETED', 'DELETED')
);
If you want multiple counts, then filtering like this does not work. So aggregate by job first:
select sum(is_created) as num_created,
sum(is_cancelled) as num_cancelled,
sum(is_created * (1 - is_cancelled) * (1 - is_completed) * (1 - is_deleted)) as open
from (select job,
max(case when status_code = 'CREATED' then 1 else 0 end) as is_created,
max(case when status_code = 'CANCELLED' then 1 else 0 end) as is_cancelled,
max(case when status_code = 'COMPLETED' then 1 else 0 end) as is_completed,
max(case when status_code = 'DELETED' then 1 else 0 end) as is_deleted
from t
group by job
) j
The following returns the result you need:
WITH TAB (Job_ID, JOB) AS
(
VALUES
(123, 'CREATED')
, (123, 'COMPLETED')
, (521, 'CREATED')
, (521, 'CANCELLED')
, (645, 'CREATED')
)
SELECT
Job_ID
, COUNT(CASE A1.JOB WHEN 'CREATED' THEN 1 END) AS CREATED
, COUNT(CASE A1.JOB WHEN 'CANCELLED' THEN 1 END) AS CANCELLED
, CASE
WHEN NULLIF(COUNT(1), 0) = COUNT(CASE A1.JOB WHEN 'CREATED' then 1 END)
THEN 1
ELSE 0
END AS OPEN
FROM TAB A1
GROUP BY JOB_ID;
With conditional aggregation:
SELECT
JobID,
MAX(CASE Status_code WHEN 'CREATED' THEN 1 ELSE 0 END) AS CREATED,
MAX(CASE Status_code WHEN 'CANCELLED' THEN 1 ELSE 0 END) AS CANCELLED,
MIN(CASE WHEN Status_code <> 'CREATED' THEN 0 ELSE 1 END) AS OPEN
FROM tablename
GROUP BY JobID
See the demo.
Results:
> JobID | CREATED | CANCELLED | OPEN
> ----: | ------: | --------: | ---:
> 123 | 1 | 0 | 0
> 521 | 1 | 1 | 0
> 645 | 1 | 0 | 1
Assuming valid close status is either "COMPLETED" or "CANCELLED", you can try following SQL.
SELECT
A1.JobID,
sum(CASE WHEN A1.Status_code = 'CREATED' THEN 1 ELSE 0 END) AS CREATED,
sum(CASE WHEN A1.Status_code = 'CANCELLED' THEN 1 ELSE 0 END) AS CANCELLED,
(
SUM(CASE WHEN A1.Status_code = 'CREATED' THEN 1 ELSE 0 END)
- sum(CASE WHEN A1.Status_code = 'CANCELLED' THEN 1 ELSE 0 END)
- sum(CASE WHEN A1.Status_code = 'COMPLETED' THEN 1 ELSE 0 END)
) AS OPEN
FROM SCHEMA.TABLE A1
GROUP BY A1.JobID

SQL How do I transpose and group data into static columns? [duplicate]

This question already has answers here:
TSQL Pivot without aggregate function
(9 answers)
Closed 4 years ago.
I have a table with the following data:
UID LAST FIRST FUND AMOUNT STATUS
1 Smith John C 100 1
1 Smith John B 250 1
1 Smith John E 150 1
2 Jones Meg B 275 1
2 Jones Meg F 150 1
3 Carter Bill A 100 1
I would like to transpose the FUND, AMOUNT and STATUS values for each UID into a single row for each UID. The resulting table would have columns added for FUND_1, AMT_1, STATUS_1, FUND_2, AMT_2, STATUS_2, FUND_3, AMT_3, STATUS_3. Each UID may or may not have a total of 3 funds. If they do not, the remaining fund, amt, and status columns are left blank. The resulting table would appear as:
UID LAST FIRST FUND_1 AMT_1 STATUS_1 FUND_2 AMT_2 STATUS_2 FUND_3 AMT_3 STATUS_3
1 Smith John C 100 1 B 250 1 E 150 1
2 Jones Meg B 275 1 F 150 1
3 Carter Bill A 100 1
For clarification, this is how the data would move from the existing table to the resulting table for UID 1:
It seems I am unable to use PIVOT because FUND_1, FUND_2, FUND_3 will be different fund categories for each person. The question, TSQL Pivot without aggregate function helps but doesn't answer my question since I have multiple rows in what would be the the DBColumnName in that question.
This is a pretty common conditional aggregation. Notice how I posted consumable data as a table and insert statements. To be honest it took longer to do that portion than the actual code to select the data. You should do this in the future. Also you should avoid using keywords as column names.
declare #Something table
(
UID int
, LAST varchar(10)
, FIRST varchar(10)
, FUND char(1)
, AMOUNT int
, STATUS int
)
insert #Something values
(1, 'Smith', 'John', 'C', 100, 1)
, (1, 'Smith', 'John', 'B', 250, 1)
, (1, 'Smith', 'John', 'E', 150, 1)
, (2, 'Jones', 'Meg', 'B', 275, 1)
, (2, 'Jones', 'Meg', 'F', 150, 1)
, (3, 'Carter', 'Bill', 'A', 100, 1)
;
with SortedValues as
(
select *
, RowNum = ROW_NUMBER() over(partition by UID order by (select null))
from #Something
)
select UID
, Last
, First
, Fund_1 = max(case when RowNum = 1 then Fund end)
, Amt_1 = max(case when RowNum = 1 then Amount end)
, Status_1 = max(case when RowNum = 1 then Status end)
, Fund_2 = max(case when RowNum = 2 then Fund end)
, Amt_2 = max(case when RowNum = 2 then Amount end)
, Status_2 = max(case when RowNum = 2 then Status end)
, Fund_3 = max(case when RowNum = 3 then Fund end)
, Amt_3 = max(case when RowNum = 3 then Amount end)
, Status_3 = max(case when RowNum = 3 then Status end)
from SortedValues
group by UID
, Last
, First
order by UID
, Last
, First

SQL Query to get count of one status + all other status as one

I have a table which holds a set of records. Now through SQL I am getting a Count for each different status. Example from the table below:
Status | ID
-------------------------
Open | 1
Open | 2
Open | 3
Open | 4
In Progress | 5
In Progress | 6
In Progress | 7
Closed | 8
Closed | 9
Closed | 10
Closed | 11
So Far I managed to do the following
Status | ID
-------------------------
Open | 4
In Progress | 3
Closed | 4
However I want the result to return
Status | ID
-------------------------
Other | 7
Closed | 4
The following is my SQL so far:
SELECT myStatus,Count(job) As CountJobs
FROM JobsTable
GROUP BY myStatus
ORDER BY CountJobs DESC
How can I achieve this?
Use a CASE expression:
SELECT CASE WHEN myStatus = 'Closed' THEN 'Closed' ELSE 'Other' END myStatus,
COUNT(*) CountJobs
FROM JobsTable
GROUP BY CASE WHEN myStatus = 'Closed' THEN 'Closed' ELSE 'Other' END;
SELECT CASE
WHEN Status = 'Closed'
THEN Status
ELSE 'OTHER'
END AS Status,
Count(job) As CountJobs
FROM JobsTable
GROUP BY CASE
WHEN Status = 'Closed'
THEN Status
ELSE 'OTHER'
END
ORDER BY CountJobs DESC
You could modify the query to use a CASE statement to replace anything other than Closed with Other in a subquery and GROUP the results of that:
SELECT [Status] ,
COUNT([Status]) StatusCount
FROM ( SELECT CASE WHEN [Status] != 'Closed' THEN 'Other'
ELSE [Status]
END AS [Status]
FROM JobsTable
) t
GROUP BY [Status]
ORDER BY StatusCount DESC
Full testable query:
CREATE TABLE #JobsTable
([Status] varchar(11), [ID] int)
;
INSERT INTO #JobsTable
([Status], [ID])
VALUES
('Open', 1),
('Open', 2),
('Open', 3),
('Open', 4),
('In Progress', 5),
('In Progress', 6),
('In Progress', 7),
('Closed', 8),
('Closed', 9),
('Closed', 10),
('Closed', 11)
;
SELECT [Status] ,
COUNT([Status]) StatusCount
FROM ( SELECT CASE WHEN [Status] != 'Closed' THEN 'Other'
ELSE [Status]
END AS [Status]
FROM #JobsTable
) t
GROUP BY [Status]
ORDER BY StatusCount DESC
DROP TABLE #JobsTable
Produces:
Status StatusCount
Other 7
Closed 4
Demo SQL Fiddle
Another solution: use WITH clause as below
WITH src AS (
SELECT CASE WHEN status = 'Closed' THEN 'Closed'
ELSE 'Other'
END as Status,
Id
from JobsTable)
SELECT src.Status, count(src.Id)
FROM src
GROUP BY src.Status;

SQL server Procedure modification required

I have a stored procedure which produces output like:
Success Fail Progress
----------------------------
1 2 3
But I want the output to be:
Recieved Count
----------------
success 1
----------------
fail 2
----------------
progress 3
Please can someone help me get this output from my sql server.
The current SQL:
select
sum(case when status='AK' then 1 else 0 end) as 'SUCCESS',
sum(case when status='E' then 1 else 0 end) as 'FAILURE',
sum(case when status NOT IN('AK','E')then 1 else 0 end) as 'PENDING'
from t
where [rec_datetime] BETWEEN '2008-02-11' AND DATEADD(DAY,1,'2008-02-11')
You can use UNPIVOT to move columns to rows:
SELECT b.[Received], b.[Count]
FROM (SELECT[Success] = 1, [Fail] = 2, [Progress] = 3) a
UNPIVOT ([Count] FOR [Received] IN ([Success], [Fail], [Progress])) b
Output
Received Count
----------- -----------
Success 1
Fail 2
Progress 3
replace your select statement with
select 'Success' as Received, sum(case when status='AK' then 1 else 0 end) as [count]
from t where [rec_datetime] BETWEEN '2008-02-11' AND DATEADD(DAY,1,'2008-02-11')
union all
select 'Fail', sum(case when status='E' then 1 else 0 end)
from t where [rec_datetime] BETWEEN '2008-02-11' AND DATEADD(DAY,1,'2008-02-11')
union all
select 'Progress' , sum(case when status NOT IN('AK','E')then 1 else 0 end)
from t where [rec_datetime] BETWEEN '2008-02-11' AND DATEADD(DAY,1,'2008-02-11')
tough without seeing your code or your data, but something like this might work:
select 'success' As Recieved, Success As [Count] from mytable
union all
select 'fail', Fail from mytable
union all
select 'progress', Progress from mytable

I would like to combine ROLLUP with PIVOT - is that an option?

I have been using
SELECT
Author,
ISNULL(MAX(CASE Status WHEN 'Duplicate' THEN NumDocs END),'') AS Duplicate,
ISNULL(MAX(CASE Status WHEN 'Failure' THEN NumDocs END),'') AS Failure,
ISNULL(MAX(CASE Status WHEN 'Rejected' THEN NumDocs END),'') AS Rejected,
ISNULL(MAX(CASE Status WHEN 'Success' THEN NumDocs END),'') AS Success,
ISNULL(MAX(CASE Status WHEN 'TOTAL' THEN NumDocs END),'') AS TOTAL
FROM
(SELECT
CASE WHEN (GROUPING(Author)=1) THEN 'ALL'
ELSE ISNULL(Author,'UNKNOWN') END AS Author,
CASE WHEN (GROUPING(Status )=1) THEN 'TOTAL'
ELSE ISNULL(Status ,'UNKNOWN') END AS [Status],
COUNT(Status) AS NumDocs
FROM
tbl_Document D
LEFT JOIN
tbl_Status S
ON
D.status_id = S.status_id
GROUP BY
Author,
Status
WITH ROLLUP) BASE
GROUP BY
Author
To transform:
[Author] [Status]
Alan SUCCESS
Bob FAILURE
Bob SUCCESS
Charles SUCCESS
Dave FAILURE
Dave DUPLICATE
TO:
[Author] [SUCCESS] [FAILURE] [DUPLICATE] [TOTALS]
Alan 1 0 0 1
Bob 1 1 0 2
Charles 1 0 0 1
Dave 0 1 1 2
TOTAL 3 2 1 6
I can get close to this output using a PIVOT statement, but I'm not sure how to get the TOTAL row/column?
SELECT
*
FROM
(SELECT Author, status_id FROM tbl_Document) d
PIVOT
(COUNT(status_id) FOR status_id IN ([1],[3],[5],[6])) p
Gives:
[Author] [SUCCESS] [FAILURE] [DUPLICATE]
Alan 1 0 0
Bob 1 1 0
Charles 1 0 0
Dave 0 1 1
I'm guessing I need to put the ROLLUP into a subquery somewhere...?
You didn't post the table schema, so I tried to infer it. I started with the input you gave (see the comment in the innermost SELECT), so you should be able to adapt this to your actual schema. I included an extra author without any documents, because I figured you'd want to see those in the final report output. It's trivial to exclude those authors.
DECLARE #Status table
(
Id int NOT NULL,
Status nvarchar(50) NOT NULL
)
DECLARE #Authors table
(
Id int NOT NULL,
Name nvarchar(50) NOT NULL
)
DECLARE #Documents table
(
Id int NOT NULL,
AuthorId int NOT NULL,
StatusId int NOT NULL
)
INSERT INTO #Status VALUES (1, 'Duplicate')
INSERT INTO #Status VALUES (2, 'Failure')
INSERT INTO #Status VALUES (3, 'Rejected')
INSERT INTO #Status VALUES (4, 'Success')
INSERT INTO #Authors VALUES (1, 'Alan')
INSERT INTO #Authors VALUES (2, 'Bob')
INSERT INTO #Authors VALUES (3, 'Charles')
INSERT INTO #Authors VALUES (4, 'Dave')
INSERT INTO #Authors VALUES (5, 'Tom') -- Test for authors without documents
INSERT INTO #Documents VALUES (1, 1, 4)
INSERT INTO #Documents VALUES (2, 2, 2)
INSERT INTO #Documents VALUES (3, 2, 4)
INSERT INTO #Documents VALUES (4, 3, 4)
INSERT INTO #Documents VALUES (5, 4, 2)
INSERT INTO #Documents VALUES (6, 4, 1)
SELECT
(CASE WHEN GROUPING(Name) = 1 THEN 'Total' ELSE Name END) AS Author,
SUM(Duplicate) AS Duplicate,
SUM(Failure) AS Failure,
SUM(Rejected) AS Rejected,
SUM(Success) AS Success,
SUM(Duplicate + Failure + Rejected + Success) AS Total
FROM
(
SELECT
Name,
(CASE WHEN Status = 'Duplicate' THEN 1 ELSE 0 END) AS Duplicate,
(CASE WHEN Status = 'Failure' THEN 1 ELSE 0 END) AS Failure,
(CASE WHEN Status = 'Rejected' THEN 1 ELSE 0 END) AS Rejected,
(CASE WHEN Status = 'Success' THEN 1 ELSE 0 END) AS Success
FROM
(
-- Original input
SELECT
a.Name,
s.Status
FROM #Authors a
LEFT OUTER JOIN #Documents d ON d.AuthorId = a.Id
LEFT OUTER JOIN #Status s ON d.StatusId = s.Id
) i
) j
GROUP BY Name WITH ROLLUP
Output:
Author Duplicate Failure Rejected Success Total
Alan 0 0 0 1 1
Bob 0 1 0 1 2
Charles 0 0 0 1 1
Dave 1 1 0 0 2
Tom 0 0 0 0 0
Total 1 2 0 3 6