Set a variable based on an IF statement in SQL Manager - sql-manager

I have a table called Ordhdr, i want to create a query based on the [status] column of that table. I have many statuses that i want to group into Won, Lost, Pending for easier viewing. How do i set my declare, set statement to first 'rename' the current status to WON, LOST or PENDING so i can then display my query results using the new name.
Sample Data
Order 1, STatus is QteCall1 (Pending Status)
Order 2, Status is Converted (Won Status)
Order 3, STatus is Declined (Dead Status)
Order 4, Status is Waiting (Pending Status)
Order 5, Status is NOResponse (Dead Status)'
how would I 'rename' the current status to get results
that showed a count of
1 Won
2 Pending
2 Dead

Is this what you need?
SELECT CASE WHEN STATUS = 'Converted' THEN 'WON'
WHEN STATUS IN ('QteCall1','Waiting') THEN 'PENDING'
WHEN STATUS IN ('Declined', 'NOResponse ') THEN 'LOST' END AS NEW_NAME
--The above case expression is being used to compare and rename the values according to the desired match
,COUNT(*) AS COUNT
FROM Ordhdr
GROUP BY
CASE WHEN STATUS = 'Converted' THEN 'WON'
WHEN STATUS IN ('QteCall1','Waiting') THEN 'PENDING'
WHEN STATUS IN ('Declined', 'NOResponse ') THEN 'LOST' END
-- This second case expression is the same as the previous one, but it is required by the SQL standards to be in the GROUP BY section
Result from query.

Related

Count number of applications that received a decision by their category?

My table has 4 columns in it.
status: (This is a string that is either pended, accepted, or rejected value of P, A, or R)
source: (this is a code like BBQ5)
id: (this is a unique identifier number)
So a row would be something like
Accepted GBBG 2109202
I want to order them by how many got accepted/ rejected / pended per source
I came up with this.
SELECT status , count(status)
FROM myTable
WHERE source in (
'BB5',
'GGG',
'FEV'
)
GROUP BY status
this gives me the number of rejected count but I need it specified per code is this possible in sql ?
use a case when for the Status categories
SELECT
source,
sum(case when status='accepted' then 1 end) accepted_count,
sum(case when status='rejected' then 1 end) rejected_count
FROM myTable
WHERE source in (
'BB5',
'GGG',
'FEV'
)
group by source

Retrieve the total number of orders made and the number of orders for which payment has been done

Retrieve the total number of orders made and the number of orders for which payment has been done(delivered).
TABLE ORDER
------------------------------------------------------
ORDERID QUOTATIONID STATUS
----------------------------------------------------
Q1001 Q1002 Delivered
O1002 Q1006 Ordered
O1003 Q1003 Delivered
O1004 Q1006 Delivered
O1005 Q1002 Delivered
O1006 Q1008 Delivered
O1007 Q1009 Ordered
O1008 Q1013 Ordered
Unable to get the total number of orderid i.e 8
select count(orderid) as "TOTALORDERSCOUNT",count(Status) as "PAIDORDERSCOUNT"
from orders
where status ='Delivered'
The expected output is
TOTALORDERDSCOUNT PAIDORDERSCOUNT
8 5
I think you want conditional aggregation:
select count(*) as TOTALORDERSCOUNT,
sum(case when status = 'Delivered' then 1 else 0 end) as PAIDORDERSCOUNT
from orders;
Try this-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
SUM(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE 0 END ) PAIDORDERSCOUNT
FROM ORDER
You can also use COUNT in place of SUM as below-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
COUNT(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE NULL END ) PAIDORDERSCOUNT
FROM ORDER
you could use cross join between the two count
select count(orderid) as TOTALORDERSCOUNT, t.PAIDORDERSCOUNT
from orders
cross join (
select count(Status) PAIDORDERSCOUNT
from orders where Status ='Delivered'
) t
What I've used in the past for summarizing totals is
SELECT
count(*) 'Total Orders',
sum( iif( orders.STATUS = 'Delivered', 1, 0 ) ) 'Total Paid Orders'
FROM orders
I personally don't like using CASE WHEN if I don't have to. This logic may look like its a little too much for a simple summation of totals, but it allows for more conditions to be added quite easily and also just involves less typing, at least for what I use this regularly for.
Using the iif( statement to set up the conditional where you're looking for all rows in the STATUS column with the value 'Delivered', with this set up, if the status is 'Delivered', then it marks it stores a value of 1 for that order, and if the status is either 'Ordered' or any other value, including null values or if you ever need a criteria such as 'Pending', it would still give an accurate count.
Then, nesting this within the 'sum' function totals all of the 1's denoted from your matched values. I use this method regularly for report querying when there's a need for many conditions to be narrowed down to a summed value. This also opens up a lot of options in the case you need to join tables in your FROM statement.
Also just out of personal preference and depending on which SQL environment you're using this in, I tend to only use AS statements for renaming when absolutely necessary and instead just denote the column name with a single quoted string. Does the same thing, but that's just personal preference.
As stated before, this may seem like it's doing too much, but for me, good SQL allows for easy change to conditions without having to rewrite an entire query.
EDIT** I forgot to mention using count(*) only works if the orderid's are all unique values. Generally speaking for an orders table, orderid is an expected unique value, but just wanted to add that in as a side note.
SELECT DISTINCT COUNT(ORDERID) AS [TOTALORDERSCOUNT],
COUNT(CASE WHEN STATUS = 'ORDERED' THEN ORDERID ELSE NULL END) AS [PAIDORDERCOUNT]
FROM ORDERS
TotalOrdersCount will count all distinct values in orderID while the case statement on PaidOrderCount will filter out any that do not have the desired Status.

How to conditionally select records from SQL Server

Friends,
I have a SQL problem I could use help on. I'm working with SQL Server 2008.
The use case is the following. We have a system where users watch videos, and each time a user watches a video, we record that activity. We capture three properties each time; assetid (an asset is a video), customerid, and status.
A record can have three different statuses; 'completion', 'playing', and 'start'.
The person who wrote this part of the system is not a developer, and instead of of updating the status of an existing record, inserts a new duplicate record each time a user watches a video. Therefore we have thousands of duplicate records. Here is a sample dataset
The problem I need to solve is to select a record by assetid, customerid, and status. I need to choose a record that has a status of 'completion' if it exists.
If a record has a status of 'playing', but no record with the same assetid and customerid with a status of 'completion' exists, then choose that record.
If a record has a status of 'start', but no record with the same assetid and customerid with a status of either 'completion' or 'playing' exists, then choose that record.
Here is sample code where I tried to use a CASE statement to solve the problem. I also tried another case statement with a NOT IN subquery, but without success.
INSERT INTO #ViewTime (AssetID, CustomerID, ViewTime)
SELECT
tt.customerid, tt.assetId, tt.assetstatus,
CASE WHEN
tt.AssetStatus = 'COMPLETION'
AND
ISNUMERIC(timeposition) = 1
THEN
CONVERT(Numeric(18,3), timePosition)
WHEN
tt.AssetStatus = 'PLAYING'
AND
ISNUMERIC(timeposition) = 1
THEN
CONVERT(Numeric(18,3), timePosition)
WHEN
tt.AssetStatus = 'START'
AND
ISNUMERIC(timeposition) = 1
THEN
CONVERT(Numeric(18,3), timePosition)
ELSE null
END AS ViewTime
FROM
TableAssetTracking tt
inner join TableAssets ta
on tt.AssetID = ta.AssetID
WHERE
tt.timePosition is not null
AND
AssetBuffering is null
Any suggestions would be greatly appreciated. Thanks, Derek
The problem I need to solve is to select a record by assetid, customerid, and status.
I need to choose a record that has a status of 'completion' if it exists.
select distinct assetID, CustomerID
from table
where status = 'complete'
If a record has a status of 'playing', but no record with the same assetid and customerid with a status of 'completion' exists, then choose that record.
select assetID, CustomerID
from table
where status = 'playing'
except
select assetID, CustomerID
from table
where status = 'complete'
If a record has a status of 'start', but no record with the same assetid and customerid with a status of either 'completion' or 'playing' exists, then choose that record.
select assetID, CustomerID
from table
where status = 'start'
except
select assetID, CustomerID
from table
where status in ('complete', 'playing')
The above is not going to give you ViewTime that I see in the example
It was not in the requirements statement
select *
from
( select assetID, CustomerID, status, ViewTime
, row_number() over (partition by assetID, CustomerID order by status, ViewTime desc) as rn
from table
where status in ('complete', 'playing', 'start')
) tt
where tt.rn = 1
There are numerous ways to do this. Here is one.
I am going to use psuedocode because the tables in your sample code don't match the description in your question. You will have to adapt this technique to your tables.
SELECT DISTINCT t.AssetId, t.CustomerId, (
SELECT TOP 1 Status
FROM MyTable t1
WHERE t1.AssetId=t.AssetId
AND t1.CustomerId=t.CustomerId
ORDER BY CASE t1.Status
WHEN 'Completion' THEN 0
WHEN 'Playing' THEN 1
WHEN 'Started' THEN 2
ELSE 3
END ASC
) AS Status
FROM MyTable t
I did this in order to show you a broad way of looking at your data. You want to REALLY identify the last record that was inserted into your table for each person and video. So we get the last one, and then get the status for that record.
IF OBJECT_ID('tempdb..#lastRecord') IS NOT NULL DROP TABLE #lastRecord
SELECT
max(trackingassetdatecreated) dt,
assetid,
customerid,
INTO #lastRecord
FROM
TableAssetTracking
GROUP BY
assetid,
customerid
SELECT
t.assetstatus,
lr.*
FROM
TableAssetTracking t
INNER JOIN
#lastRecord lr on
lr.trackingassetdatecreated = t.trackingassetdatecreated
and lr.assetid = t.assetid
and lr.customerid = t.customerid

SQL Count project items where project status history is within date range

I have 4 tables:
projects: id, title, current_status_id
statuses: id, label
status_history: project_id, status_id, created_at
messages: id, project_id, body, created_at
A status_history row is inserted when, in the application, the project changes status (say, from "lead" to "active" to "complete"). Note the created_at column is a timestamp that records the date of the change. Between status changes, activity is happening in the project and messages are created. For example, the project is initialized with a "lead" status, some messages are created while the project is in this "lead" state, the project is changed to "active" status, some messages are created while the project is in this state, and so on.
I want to create query that shows: date, # of messages created in "lead" projects, # messages created in "active" projects, and # messages in projects with other statuses. Can this be done all in one query? I am using PostgreSQL.
Here is some pseudo-code that hopefully illuminates what I'm looking for.
* Start at the earliest date
* Find all projects whose status was 'lead' on that date
* Count the number of created messages from these projects with that date
* Find all projects whose status was 'active' on that date
* Count the number of created messages from these projects with that date
* Find all projects whose status was anything else on that date
* Count the number of created messages from these projects with that date
* ... some projects change status, some stay the same, business happens ...
* Go to next date
* Find all projects whose status was 'lead' on that date
* Count the number of created messages from these projects with that date
* Find all projects whose status was 'active' on that date
* Count the number of created messages from these projects with that date
* Find all projects whose status was anything else on that date
* Count the number of created messages from these projects with that date
* ... some projects change status, some stay the same, business happens ...
* keep doing this until the present
While the project does have a current_status_id column, it is the present status and not necessarily the status of the project last month. The status of the project does not change every day - a status_history row is not created every day for every project.
You are looking for a query like this...This is MSSQL but I assume very similar to Postgresql or you can simply find the correct syntaxes online.
SELECT count(*) AS 'count', messages.created_at, statuses.label
FROM messages
JOIN projects ON projects.id = messages.project_id
JOIN status_history ON projects.id = status_history.project_id
JOIN statuses ON statuses.id ON status_history.status_id
GROUP BY created_at, statues.label
Try the below.
Replace "lead" and "active" with the status IDs for those 2 statuses.
Note that the first field being selected is a conversion of your created_at timestamp to a date value (removing time).
The counts provided show the number of projects newly created with those statuses. They do not include projects who were already around but which changed to those statuses on the given days. This is accomplished via the not exists subquery.
select date(created_at) as dt
, sum(case when sh.status_id = 'lead' then 1 else 0 end) as num_lead
, sum(case when sh.status_id = 'active' then 1 else 0 end) as num_active
, sum(case when sh.status_id not in ('lead','active') then 1 else 0 end) as num_else
from status_history sh
where not exists
( select 1
from status_history x
where x.project_id = sh.project_id
and x.created_at < sh.created_at )
group by date(created_at)
order by 1
what about:
SELECT to_char(tmp.date, 'YYYY-MM-DD') as date, COUNT(tmp.status = 'lead') as num_lead, COUNT(tmp.status = 'active') as num_active FROM
(
SELECT m.created_at AS date, COUNT(m.id) as messages, s.label as status FROM messages AS m
INNER JOIN project AS p ON p.id = m.project_id
INNER JOIN statuses AS s ON s.id = p.current_status_id
GROUP BY m.created_at, s.id, s.label
) as tmp
GROUP BY tmp.date;
Grouping should be 100%-correct (because it's not clear that one id belongs to exactly one textual-representation, label is not primary_key!)
Temporary table contains all relations of "Messages per date and project_status_label" and the outer select-function only changes dimension.

How to write this SQL Order By Clause

I have a SQL Query which I am trying to write and am now a bit stuck on how to write the order by clause.
Basically the table I am selecting from has items with a severity value. I want to select these items and order them so that the Severity column is ordered Severity 1-4 then 0 and the log date is descending for each.
Severity 1 is highest 4 is lowest and 0 respresents an unassigned severity, I need to display these items Highest severity, oldest item first, lowest severity, newest item last.
My query so far:
SELECT
[TicketID],
[type],
[Product],
[Description],
[LoggedBy],
[LogDate],
[Department],
[AssignedTo],
[Severity],
[Status],
[LastUpdatedBy],
[LastUpdatedDate]
FROM
SupportTicketsTbl
WHERE
TicketID NOT IN
(
SELECT
tck.ticketID
FROM
SupportTicketsTbl tck
JOIN
tblTicketsInEvents tie
ON
tck.TicketID = tie.ticketID
JOIN
tblSupportEvent ev
ON
tie.eventID = ev.id
where
ev.type = 1
)
AND
Status <> 'Complete'
I guess the easiest way is to create a table variable and select all the Items that are not 0 into it in the order I want, then select all the 0 items into my table variable, and finally just select everything back out of the table variable, but this seems a bit messy so im wondering if there is a more elegant solution?
Thanks
Since you didn't like the UNION answer, and I'm not sure if UNION is guaranteed to preserve order...
ORDER BY CASE WHEN severity = 0 THEN 999 ELSE Severity END, date
You can order by a case statement like this:
ORDER BY CASE Severity WHEN 0 THEN 1 ELSE 2 END, Severity
First, Select all of the ones with severity levels 1-4 using a standard orderby clause, then union the results with a second query that selects only the ones with severity level 0.
Unless I'm very much mistaken, it's something like this:
ORDER BY severity DESC, date DESC
Insert that line into your SQL.
This will sort the data by Severity first, and if they have the same severity, then sort it according to date.