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

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
)

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.

Nested SQL Queries with Self JOIN - How to filter rows OUT

I have an SQLite3 database with a table upon which I need to filter by several factors. Once such factor is to filter our rows based on the content of other rows within the same table.
From what I've researched, a self JOIN is going to be required, but I am not sure how I would do that to filter the table by several factors.
Here is a sample table of the data:
Name Part # Status Amount
---------------------------------
Item 1 12345 New $100.00
Item 2 12345 New $15.00
Item 3 35864 Old $132.56
Item 4 12345 Old $15.00
What I need to do is find any Items that have the same Part #, one of them has an "Old" Status and the Amount is the same.
So, first we would get all rows with Part # "12345," and then check if any of the rows have an "Old" status with a matching Amount. In this example, we would have Item2 and Item4 as a result.
What now would need to be done is to return the REST of the rows within the table, that have a "New" Status, essentially discarding those two items.
Desired Output:
Name Part # Status Amount
---------------------------------
Item 1 12345 New $100.00
Removed all "Old" status rows and any "New" that had a matching "Part #" and "Amount" with an "Old" status. (I'm sorry, I know that's very confusing, hence my need for help).
I have looked into the following resources to try and figure this out on my own, but there are so many levels that I am getting confused.
Self-join of a subquery
ZenTut
Compare rows and columns of same table
The first two links dealt with comparing columns within the same table. The third one does seem to be a pretty similar question, but does not have a readable answer (for me, anyway).
I do Java development as well and it would be fairly simple to do this there, but I am hoping for a single SQL query (nested), if possible.
The "not exists" statment should do the trick :
select * from table t1
where t1.Status = 'New'
and not exists (select * from table t2
where t2.Status = 'Old'
and t2.Part = t1.Part
and t2.Amount = t1.Amount);
This is a T-SQL answer. Hope it is translatable. If you have a big data set for matches you might change the not in to !Exists.
select *
from table
where Name not in(
select Name
from table t1
join table t2
on t1.PartNumber = t2.PartNumber
AND t1.Status='New'
AND t2.Status='Old'
and t1.Amount=t2.Amount)
and Status = 'New'
could be using an innner join a grouped select for get status old and not only this
select * from
my_table
INNER JOIN (
select
Part_#
, Amount
, count(distinct Status)
, sum(case when Status = 'Old' then 1 else 0 )
from my_table
group part_#, Amount,
having count(distinct Status)>1
and sum(case when Status = 'Old' then 1 else 0 ) > 0
) t on.t.part_# = my_table.part_#
and status = 'new'
and my_table.Amount <> t.Amount
Tried to understand what you want best I could...
SELECT DISTINCT yt.PartNum, yt.Status, yt.Amount
FROM YourTable yt
JOIN YourTable yt2
ON yt2.PartNum = yt.PartNum
AND yt2.Status = 'Old'
AND yt2.Amount != yt.Amount
WHERE yt.Status = 'New'
This gives everything with a new status that has an old status with a different price.

MS SQL Script to find rows where value does not exist

I have a situation where I have in one table record 'a' which have order number 0 and also record 'a' but with order number 1 - this is correct.
i also have record 'b' which has order number 1 and there is no row for record 'b' where order number = 0. - this is not correct.
I need to create a script which will find all records where order number = 1 but order number 0 doesn't exist. Can you guys help with this?
i cannot use simple:
SELECT DISTINCT record FROM tablename WHERE order_number <> 0
because it will give me also record 'a' which i don't want to have in results.
I was thinking about using Not Exists function but it always compares 2 tables where i have all records in one table.
Regards
Using Not Inin Where will eliminate 'a' and will give only 'b'
Try this:-
SELECT DISTINCT record FROM tablename WHERE order_number <> 0
and record not in (Select record from tablename WHERE order_number = 0);
hope this helps:-)

SUM and IF operator with SQL

I have a column in a table with values of 1 given to users who purchase a trial, and 0 given to users who do not.
I want the total of users who have purchased the trial. The unique identifier in the table is given by user_id.
Will the IF operator work? Can anyone explain why or why not?
You would just do:
select count(*) from users where trial=1
or
select sum(trial) from users
Why are you thinking to use IF?
You can use the query:
SELECT COUNT(*) FROM TABLE_NAME WHERE TRIAL=1
Or you can just specify the condition in COUNT() function itself like
select count(case trial when 1 then 1 else null end) from users
Using a SUM() function like
select sum(case when trial = 1 then 1 else 0 end) from users

Getting SUM from 2 different tables into one result

I have been trying to get this to work for 12 hrs now and I cannot :-( Can someone please show me how I can get the ssnumber to group and get the total for each ssnumber.
Here is what I have now. In Table number 1 I have this code
SELECT
UNIT_NO, SUM(RATEB) AS TOTALRTE
FROM TABLE1
WHERE
TRUCK_PAID = 1
AND PICK_UP_DATE >= '(fromdate)'
AND PICK_UP_DATE <= '(todate)'
GROUP BY
UNIT_NO
ORDER BY
UNIT_NO
But table number 2 is where the ssnumber column is, so what I'm trying to do is the rateB sum from all of the loads for each unit_no and then group them and then go into table number 2 and group the ssnumber with the unit number from table number 1 and sum the rateB from table number 1.
Something like this (see below) but its not working :-(
SELECT
UNIT_NO, SUM(RATEB)
FROM
TABLE1
WHERE
TRUCK_PAID = 1
AND PICK_UP_DATE >= '(fromdate)'
AND PICK_UP_DATE <= '(todate)'
GROUP BY
UNIT_NO
JOIN
TABLE TABLE1.UNIT_NO = TABLE2.UNIT_NO GROUP BY TABLE2.SS_NUM
or
SELECT
UNIT_NO, SUM(RATEB) AS TOTALRATE
FROM
TABLE1
GROUP BY
UNIT_NO
JOIN
TRUCKS ON (TABLE1.UNIT_NO = TABLE2.UNIT_NO)
GROUP BY
TABLE2.SSNUMBER
Thank you guys so much for any help...
As requested, it is hard to really understand what you are trying to accomplish without more info about table2 and maybe an example of what you are expecting. However, what I got from your description is that you are trying to accomplish something like this?
SELECT UNIT_NO, TOTALRTE, TOTALLDSRTE
FROM
(
SELECT UNIT_NO,SUM(RATEB) AS TOTALRTE
FROM LOADS
GROUP BY UNIT_NO
) AS tbl1
JOIN
(
SELECT SS_NUM, SUM(RATEB) AS TOTALLDSRTE
FROM LOADS
GROUP BY SS_NUM
) AS tbl2
ON tbl1.UNIT_NO = tbl2.SS_NUM
I would suggest instead of getting data from two select queries in one select query, try to fetch them as separate queries. This saves a lot of time. That, or you can create a table for the result and update the result of each query into the table.