force a ceiling to count(*) in sql query - sql

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

Related

Determine if any values satisfy a condition

How do I write an effiecient query to determine if 1 or more values are 10+ in a column. I am aware that I can count the values but this will scan all the records. Here is what I have so far:
SELECT COUNT(*) FROM MyTable WHERE [state] = 12 AND age > 110
I want this query to stop when it find the first person over 110 not scan the entire table. Is this possible?
You can use a subquery to return 1 or no row using this query:
SELECT TOP 1 1 as row_exists
FROM MyTable
WHERE [state] = 12 AND age > 110;
You can use a subquery to return 1 or NULL using this as a subquery:
SELECT (SELECT TOP 1 1 FROM MyTable WHERE [state] = 12 AND age > 110
) as row_exists;
You can put this into T-SQL using:
IF (EXISTS (SELECT 1 FROM MyTable WHERE [state] = 12 AND age > 110))
BEGIN
. . .
END;
TOP is not needed in an EXISTS subquery.
So you wish to have the scalar Boolean result? The exists will quite once any row matches the condition
DECLARE #Result bit =
(SELECT CASE WHEN EXISTS(SELECT * FROM MyTable WHERE [state] = 12 AND age > 110) THEN 1 ELSE 0 END)
I am not sure wether the it is helpful for you, but you can try to test:
For example you can want to determine the result set row count is 100.
you can use top 100 base your statement.
if the orignal result lines is more than 100, then ##ROWCOUNT will be true.
SELECT TOP 100 FROM MyTable WHERE [state] = 12 AND age > 110
IF ##ROWCOUNT=100
PRINT 'True'
ELSE
PRINT 'Flase'

counting groups which contain an element with a certain attribute

I have a table containing 3 values
CREATE TABLE x (
start integer NOT NULL,
end integer NOT NULL,
random integer NOT NULL);
I want to count the amount of groups (GROUP BY start,end) that contain at least one element with random > 42 but are bigger than one element. But as far as I know HAVING can only be used with aggregate functions.
My current attempt:
SELECT count(*) FROM (
SELECT count(*) FROM routes
GROUP BY start,end
HAVING random > 42
AND count(*) > 1);
results in
no such column: random
What would be the most efficient way to solve this problem?
SELECT count(*)
FROM (SELECT SUM(case when random > 42 then 1 else 0 end) as cnt
FROM routes
GROUP BY start,end
HAVING count(*) > 1) as t
WHERE cnt > 1
Include the condition in your aggregate function itself like below
SELECT count(case when random > 42 then 1 else 0 end) as computed_column
FROM routes
GROUP BY start, end;
Your query is bit weird, it can be re-written like
SELECT COUNT(*) FROM
(
SELECT count(*) as Count_Route
FROM routes
WHERE random > 42
GROUP BY start, end
HAVING count(*) > 1
) XXX;

Sqlite optimizing query using case when

I have three tables A,B and C. I have to detect if any of them have zero rows. As soon as any table with zero row is detected, I do not need to check other ones.
So, one way is I execute three queries separately and after each query I check the number of returned rows. If its non-zero then only I execute the query of next table.
Second way is I write a single query using case-when, something like
select case
when (select count(*) from A = 0)
then 1
else (
select case
when (select count(*) from B = 0)
then 1
else (
select case
when (select count(*) from B = 0)
then 1
else 0
)
)
end as matchResult;
The second method requires lesser code as I have to write a single query and db will do the comparison for me.
My question is whether its overkilling or can I further optimize the query?
EDIT
On further study, I realise that the query above is wrong. However, I can simply do it as
select case
when (select count(*) from A) = 0 and
(select count(*) from B) = 0 and
(select count(*) from C) = 0
then 1
else 0
end as matchResult;
and if I am not wrong, and conditions are checked from left to right and if any one is false, conditions to the right are not checked.
Please confirm this point.
Count is kind of expensive
select 1
where not exits (select * from a)
or not exits (select * from b)
or not exits (select * from c)
One query with three resutls:
select (select count(*) from A) as Acount,
(select count(*) from B) as Bcount,
(select count(*) from C) as Ccount
This instead gives name of the fitst table that is empty:
select case
when (select count(*) from A)=0 then 'A'
when (select count(*) from B)=0 then 'B'
when (select count(*) from C)=0 then 'C'
else 'ops, all have records' -- remove this to have a null
end as first_empty_table

SQL if select statement returns no rows then perform alternative select statement

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.

Simplifying CASE WHEN SQL statement

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