I need to determine whether a customer has bought 100 or more unique drinks using a SQL query and so far I've done:
SELECT COUNT(DISTINCT beer_id)
FROM Orders
WHERE patron_email='smith#gmail.com'
How would I test whether the result of this is 100 or more?
Update: Sorry for the vague question, I need to use standard SQL.
This works in MySQL, not sure about others:
SELECT COUNT(DISTINCT beer_id) > 100
FROM Orders
WHERE patron_email='smith#gmail.com'
Just put a boolean condition in the SELECT. It will evaluate to 0 for false or 1 for true.
By using the having clause as in:
SELECT COUNT(DISTINCT beer_id)
FROM Orders
WHERE patron_email='smith#gmail.com'
having count(distinct beer_id) > 100
You could use CASE with a sub-query which produces a single row:
SELECT CASE WHEN (SELECT COUNT(DISTINCT beer_id)
FROM Orders
WHERE patron_email='smith#gmail.com') > 100
THEN 'More than 100' ELSE 'Not more than 100' END As ColumnName
Try this:
SELECT COUNT(beer_id)
FROM Orders
WHERE patron_email='smith#gmail.com'
group by beer_id
having COUNT(beer_id) > 100
Assuming T-SQL
DECLARE #result AS INT
DECLARE #boolean AS INT
SET #result = ( SELECT COUNT(DISTINCT beer_id)
FROM Orders
WHERE patron_email='smith#gmail.com')
IF #result > 100
BEGIN
SET #boolean = 1
END
ELSE
BEGIN
SET #boolean = 0
END
or one more :
select case when (count(distinct beer_id)>100) then 1
else 0 end
from orders where patron_email='.....'
The EXISTS operator yields a boolean:
SELECT EXISTS (
SELECT 12345
FROM orders
GROUP BY customer_id
HAVING COUNT(beer_id) > 100
) AS at_least_one_customer_ordered_100_different_beers
;
Related
I have the following select statement in Redshift that will return rows with certain values if the condition inside is met. I want to transform this into a DQ check which will return 1 (True) if no rows ae returned or 0 if any row is returned, but I do not know where I should apply the case statement.
Here is the select statement:
select * from (select brand,calendar_dt, product,
count(account) count from revenue_base
where player_days = 0 and volume_loc >0 group by brand,calendar_dt, product)
where count > 1000 and calendar_dt >='2020-07-12'
and calendar_dt < '2020-07-13'
Can you please offer me some ideas for this?
You may try using exists logic here:
select
case when not exists (
select 1 from
(
select brand, calendar_dt, product, count(account) as count
from revenue_base
where player_days = 0 and volume_loc > 0
group by brand, calendar_dt, product
) t
where calendar_dt >= '2020-07-12' and calendar_dt < '2020-07-13' and
count > 1000
)
then 1 else 0 end as result;
First, Redshift supports booleans, so case is not needed. Second, do the filtering on the date before the aggregation. This is usually faster.
Then, you can filter by the count using a having clause, so no subquery is needed:
select not exists (select 1
from revenue_base
where player_days = 0 and volume_loc > 0 and
calendar_dt >= '2020-07-12' and calendar_dt < '2020-07-13'
group by brand, calendar_dt, product
having count(*) > 1000
) as result
I'm struggling to figure this one out.
What I want to do is like so:
select [fields],
((select <criteria>) return 0 if no rows returned, return 1 if any rows returned) as SubqueryResult
where a=b
Is this possible?
Please try:
select [fields],
case when (select COUNT(*) from YourTable with criteria)>0 then
1
else
0
end
as SubqueryResult
where a=b
In T-sql you can use Exists clause for the given requirement as:
select [fields],
case when exists (select <criteria> from <tablename> ) then 1
else 0
end as SubqueryResult
from <tablename>
where a=b
Also in TSQL you can do it using ISNULL() and SELECT TOP 1:
select [fields],
ISNULL((SELECT TOP 1 1 FROM YourTable WHERE <criteria> ),0)
as SubqueryResult
where a=b
Basically, what syntex would allow me to achieve the title statement?
If (select statement 1) returns 0 rows THEN (select statement 2) else (select statement 3)
So that the sql returns results from either statement 2 or 3
I've looked for a way to do this but nothing I've found so far seems to exactly address the if requirements.
IF EXISTS (SELECT field FROM table)
BEGIN
SELECT field FROM table2
END
ELSE
BEGIN
SELECT field FROM table3
END
Here you go...
IF ((select count(*) from table1)= 0)
BEGIN
Select * from table2
END
ELSE
BEGIN
SELECT * from table3
END
Sorry for the lack of feedback. Someone else in the office took an interest and came up with this:
select * from (
select *
, (SELECT Count(*)
FROM users
WHERE version_replace = 59 AND moderated = 1) AS Counter
FROM users WHERE version_replace = 59 AND moderated in (0,1)
) AS y
where Counter = 0 and Moderated = 0
or Counter > 0 and Moderated = 1
ORDER By ID DESC
Which does what I need.
Im trying to improve the following CASE statement to calculate the difference only once. I do it to avoid negative numbers:
SELECT (CASE WHEN ((SELECT 100 - (SELECT COUNT(CustomerId) FROM Customers)) > 0)
THEN (SELECT 100 - (SELECT COUNT(CustomerId) FROM Customers))
ELSE (0)
END)
This not only looks stupid, but also is not thread-safe. I tried the following, but I get an error message "Invalid column name 'diff'."
SELECT (CASE WHEN ((SELECT 100 - (SELECT COUNT(CustomerId) FROM Customers) as diff) > 0)
THEN (diff)
ELSE (0)
END)
How can this be simplified? Is there an in-built SQL function that already does this job?
EDIT: Sorry, forgot to mention that the select statement is inside of a view declaration, so I cant declare variables.
If I follow your logic right, this should do it:
SELECT COALESCE ((SELECT 100 - COUNT(CustomerID)
FROM Customers
HAVING COUNT(CustomerID) < 100), 0)
Slightly more graceful.
If there was a row-based MAX() function, we could use that too. Of course you could write one easily enough.
DECLARE #diff int
SELECT #diff = 100 - COUNT(*) FROM Customers
SELECT CASE WHEN #diff > 0 THEN diff
ELSE 0
END as Diff
You could use a variable to start the result of the query so you don't have to execute it twice. For example:
DECLARE #CustomerCount INT
SELECT #CustomerCount = COUNT(CustomerId) FROM Customers
SELECT CASE WHEN (100 - #CustomerCount > 0)
THEN 100 - #CustomerCount
ELSE (0)
END
You are right, you only want to count once and you want to do it so it clearly shows what your logic is.
SELECT CASE WHEN cnt > 100 THEN 0
ELSE 100 - cnt END AS diff
FROM (SELECT COUNT(1) AS cnt
FROM Customers) AS CustomerCnt
I am using a subquery to return a count as an integer value to my main query. This query is used to rebind an ASP.NET DataGrid and I have only two characters width available for this column. I want to restrict the width to two characters. So, I want to set a value of 99 when the count exceeds 99. I can't figure a way to do this? I can't see how to apply a case statement here.
SELECT
MEMB_ID,
MEMB_Name,
SELECT COUNT(*)
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = m.MEMB_ID
And SessionOrder.SORD_NumberCompleteDownloads <> 0
As MEMB_Downloads,
MEMB_JoinDate
FROM Member
How can this be done?
Replace
COUNT(*)
With
CASE WHEN COUNT(*) > 99 THEN 99 ELSE COUNT(*) END AS YourColumnName
The CASE expression can look like this:
CASE WHEN COUNT(*) > 99 THEN 99 ELSE COUNT(*) END
There appear to be a couple of errors with your existing query (for example m is not defined). With these errors corrected and the above change made the resulting query could look like this:
SELECT
MEMB_ID,
MEMB_Name,
(
SELECT CASE WHEN COUNT(*) > 99 THEN 99 ELSE COUNT(*) END
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = MEMB_ID
AND SessionOrder.SORD_NumberCompleteDownloads <> 0
) AS MEMB_Downloads,
MEMB_JoinDate
FROM Member
This might be a bit more efficient. As it can stop scanning rows once the 99th is reached.
SELECT MEMB_ID ,
MEMB_Name,
( SELECT COUNT(*)
FROM (
SELECT TOP 99 *
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = MEMB_ID
AND SessionOrder.SORD_NumberCompleteDownloads <> 0
)
Top99
) AS MEMB_Downloads,
MEMB_JoinDate
FROM Member
Rather than change the COUNT(*) result, better count at most 99:
SELECT
MEMB_ID,
MEMB_Name,
(SELECT COUNT(*)
FROM (
SELECT TOP(99) *
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = m.MEMB_ID
And SessionOrder.SORD_NumberCompleteDownloads <> 0)
as TOP99_Downloads)
As MEMB_Downloads,
MEMB_JoinDate
FROM Member;
This way you avoid counting all the downloads when you'll only display 99 anyway. Of course, one would ask what is the point of displaying a value if is incorrect to start with and why not make your UI layer capable of displaying 'more than 99'.
CASE it should be ...
or double UNION as
SELECT
MEMB_ID,
MEMB_Name,
SELECT COUNT(*) AS WC
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = m.MEMB_ID
And SessionOrder.SORD_NumberCompleteDownloads <> 0
And WC =< 99
As MEMB_Downloads,
MEMB_JoinDate
FROM Member
UNION
SELECT
MEMB_ID,
MEMB_Name,
99 AS WC
FROM SessionOrder
WHERE SessionOrder.SORD_MEMB_ID = m.MEMB_ID
And SessionOrder.SORD_NumberCompleteDownloads <> 0
And WC > 99
As MEMB_Downloads,
MEMB_JoinDate
FROM Member