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

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

Related

using correlated subquery in the case statement

I’m trying to use a correlated subquery in my sql code and I can't wrap my head around what I'm doing wrong. A brief description about the code and what I'm trying to do:
The code consists of a big query (ALIASED AS A) which result set looks like a list of customer IDs, offer IDs and response status name ("SOLD","SELLING","IRRELEVANT","NO ANSWER" etc.) of each customer to each offer. The customers IDs and the responses in the result set are non-unique, since more than one offer can be made to each customer, and a customer can have different response for different offers.
The goal is to generate a list of distinct customer IDs and to mark each ID with 0 or 1 flag :
if the ID has AT LEAST ONE offer with status name is "SOLD" or "SELLING" the flag should be 1 otherwise 0. Since each customer has an array of different responses, what I'm trying to do is to check if "SOLD" or "SELLING" appears in this array for each customer ID, using correlated subquery in the case statement and aliasing the big underlying query named A with A1 this time:
select distinct
A.customer_ID,
case when 'SOLD' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID) OR
'SELLING' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID)
then 1 else 0 end as FLAG
FROM
(select …) A
What I get is a mistake alert saying there is no such object as A or A1.
Thanks in advance for the help!
You can use exists with cte :
with cte as (
<query here>
)
select c.*,
(case when exists (select 1
from cte c1
where c1.customer_ID = c.customer_ID and
c1.response in ('sold', 'selling')
)
then 1 else 0
end) as flag
from cte c;
You can also do aggregation :
select customer_id,
max(case when a.response in ('sold', 'selling') then 1 else 0 end) as flag
from < query here > a;
group by customer_id;
With statement as suggested by Yogesh is a good option. If you have any performance issues with "WITH" statement. you can create a volatile table and use columns from volatile table in your select statement .
create voltaile table as (select response from where response in ('SOLD','SELLING').
SELECT from customer table < and join voltaile table>.
The only disadvantge here is volatile tables cannot be accessed after you disconnect from session.

SQL to find "clients" with a specific missing attribute

Is there a way to use a SQL statement on 1 table in which the result is the clients who do NOT have one specific attribute?
The table exists of multiple columns. One of them is Clientand another one is Product. One client can have several different records with different product-values.
Every client should at least have one specific product (for example X), next to a lot of different other values of product he can have. I would like to use a statement which returns all clients who don't have product X.
There are several ways:
Using NOT EXISTS as following:
SELECT client
FROM yourTable T
WHERE NOT EXISTS
(SELECT 1 FROM yourTable TIN
WHERE TIN.product = 'product X'
AND T.CLIENT = TIN.CLIENT
);
Using NOT IN
SELECT client
FROM yourTable T
WHERE client not in
(SELECT tin.client FROM yourTable TIN
WHERE TIN.product = 'product X'
);
Using group by, as shown in the other answers
select client
from yourTable
group by client
HAVING COUNT(CASE WHEN product = 'product X' THEN 1 END) = 0;
Aggregation is one simple option:
SELECT client
FROM yourTable
GROUP BY client
HAVING COUNT(CASE WHEN product = 'product X' THEN 1 END) = 0;
This works by keeping a count, for each client, of each record which matches product X. Assuming a client never has this product, the count would be zero.
Try it with NOT IN.
SELECT *
FROM table1
WHERE product NOT IN ('X')
SELECT [Clients] FROM [tablename] WHERE Product != 'X'
Use subquery to get all records which have X and then in the main query get all records which are not in this subset:
SELECT DISTINCT table_name.client FROM table_name WHERE table_name.client NOT IN (SELECT DISTINCT table_name.client FROM table_name WHERE table_name.product = 'X')

Redshift - Finding number of times a flag appears for a particular ID

I have some sales data that shows if a bill has been generated for a customer. The column labelled bill_generated returns 'Y' if a bill has been generated else its blank. I am trying to find the list of customers for whom atleast one bill has been generated. There could be multiple rows for each cust_id as shown below:
cust_id, bill_generated
001,NULL
001,Y
002,NULL
002,NULL
003,Y
Could anyone advice on this. I am using Redshift DB. Thanks..
Try below using group by and having cluse
select cust_id from tablename
group by cust_id
having sum(case when bill_generated is null then 0 else 1 end)=1
you can use co-related sub-query
select * from t
where exists (select 1 from t t1
where t1.bill_generated='Y' and t1.cust_id=t.cust_id
)

SQL Server iterating through time series data

I am using SQL Server and wondering if it is possible to iterate through time series data until specific condition is met and based on that label my data in other table?
For example, let's say I have a table like this:
Id Date Some_kind_of_event
+--+----------+------------------
1 |2018-01-01|dsdf...
1 |2018-01-06|sdfs...
1 |2018-01-29|fsdfs...
2 |2018-05-10|sdfs...
2 |2018-05-11|fgdf...
2 |2018-05-12|asda...
3 |2018-02-15|sgsd...
3 |2018-02-16|rgw...
3 |2018-02-17|sgs...
3 |2018-02-28|sgs...
What I want to get, is to calculate for each key the difference between two adjacent events and find out if there exists difference > 10 days between these two adjacent events. In case yes, I want to stop iterating for that specific key and put label 'inactive', otherwise 'active' in my other table. After we finish with one key, we start with another.
So for example id = 1 would get label 'inactive' because there exists two dates which have difference bigger that 10 days. The final result would be like that:
Id Label
+--+----------+
1 |inactive
2 |active
3 |inactive
Any ideas how to do that? Is it possible to do it with SQL?
When working with a DBMS you need to get away from the idea of thinking iteratively. Instead you need to try and think in sets. "Instead of thinking about what you want to do to a row, think about what you want to do to a column."
If I understand correctly, is this what you're after?
CREATE TABLE SomeEvent (ID int, EventDate date, EventName varchar(10));
INSERT INTO SomeEvent
VALUES (1,'20180101','dsdf...'),
(1,'20180106','sdfs...'),
(1,'20180129','fsdfs..'),
(2,'20180510','sdfs...'),
(2,'20180511','fgdf...'),
(2,'20180512','asda...'),
(3,'20180215','sgsd...'),
(3,'20180216','rgw....'),
(3,'20180217','sgs....'),
(3,'20180228','sgs....');
GO
WITH Gaps AS(
SELECT *,
DATEDIFF(DAY,LAG(EventDate) OVER (PARTITION BY ID ORDER BY EventDate),EventDate) AS EventGap
FROM SomeEvent)
SELECT ID,
CASE WHEN MAX(EventGap) > 10 THEN 'inactive' ELSE 'active' END AS Label
FROM Gaps
GROUP BY ID
ORDER BY ID;
GO
DROP TABLE SomeEvent;
GO
This assumes you are using SQL Server 2012+, as it uses the LAG function, and SQL Server 2008 has less than 12 months of any kind of support.
Try this. Note, replace #MyTable with your actual table.
WITH Diffs AS (
SELECT
Id
,DATEDIFF(DAY,[Date],LEAD([Date],1,0) OVER (ORDER BY [Id], [Date])) Diff
FROM #MyTable)
SELECT
Id
,CASE WHEN MAX(Diff) > 10 THEN 'Inactive' ELSE 'Active' END
FROM Diffs
GROUP BY Id
Just to share another approach (without a CTE).
SELECT
ID
, CASE WHEN SUM(TotalDays) = (MAX(CNT) - 1) THEN 'Active' ELSE 'Inactive' END Label
FROM (
SELECT
ID
, EventDate
, CASE WHEN DATEDIFF(DAY, EventDate, LEAD(EventDate) OVER(PARTITION BY ID ORDER BY EventDate)) < 10 THEN 1 ELSE 0 END TotalDays
, COUNT(ID) OVER(PARTITION BY ID) CNT
FROM EventsTable
) D
GROUP BY ID
The method is counting how many records each ID has, and getting the TotalDays by date differences (in days) between the current the next date, if the difference is less than 10 days, then give me 1, else give me 0.
Then compare, if the total days equal the number of records that each ID has (minus one) would print Active, else Inactive.
This is just another approach that doesn't use CTE.

SQL select problems

I have the following table named Find, and I want to return the number of SessionID with names having both "/topic" and "/detail". Therefore, it should return 1 in my case since only SessionID=1 has both "/topic" and "/detail" in the column "name".
i tried to use the following code but i guess i messed up GROUP BY again.
Thx!
Select count( distinct `SessionID`)
from Find
where `name` like "/detail%"
and `name` like "/topic%"
group by `SessionID`, `date`
order by `date`;
I also have another column named "date" which did not show up in my screenshot. The column date tells which date the SessionID is collected. So i thought I could group by SessionID for my purpose mentioned above, and then group by date. Therefore at the end, I will know the number of SessionID meeting requirement by each day.
You need to separate your query in 2 steps. First, you need to find out the sessions containing both /details% and /topic%. Then you can count them.
Pivot rows for name lookup
SELECT
SessionID,
MAX(CASE WHEN name LIKE "/detail%" THEN 1 END) AS hasDetail,
MAX(CASE WHEN name LIKE "/topic%" THEN 1 END) AS hasTopic
FROM Find
GROUP BY SessionID
The result of the sub-query is :
SessionID hasDetail hasTopic
--------- --------- --------
1 1 1
2 1
3 1
Count the result
SELECT COUNT(*)
FROM
(
SELECT
SessionID,
MAX(CASE WHEN `name` LIKE "/detail%" THEN 1 END) AS hasDetail,
MAX(CASE WHEN `name` LIKE "/topic%" THEN 1 END) AS hasTopic
FROM Find
GROUP BY SessionID
) AS A
WHERE A.hasDetail = 1 AND A.hasTopic = 1;
This query is written for MySQL database, please let me know if you need other SQL statement, such as T-SQL for SQL Server.
You were close you just needed to include date and the count as different columns. Like this:
Select `SessionID`, `date`, count(*) as number
from Find
where `name` like "/detail%"
or `name` like "/topic%"
group by `SessionID`, `date`
order by `date`;