Determine if any values satisfy a condition - sql

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'

Related

SQL retrieval from tables

I have a table something like
EMPLOYEE_ID DTL_ID COLUMN_A COLUMN_B
---------------------------
JOHN 0 1 1
JOHN 1 3 1
LINN 0 1 12
SMITH 0 9 1
SMITH 1 11 12
It means for each person there will be one or more records with different DTL_ID's value (0, 1, 2 .. etc).
Now I'd like to create a T-SQL statement to retrieve the records with EMPLOYEE_ID and DTL_ID.
If the specified DTL_ID is NOT found, the record with DTL_ID=0 will be returned.
I know that I can achieve this in various ways such as checking if a row exists via EXISTS or COUNT(*) first and then retrieve the row.
However, I'd like to know other possible ways because this retrieval statement is very common in my application and my table have hundred thousand of rows.
In the above approach, I've had to retrieve twice even if the record with the DTL_ID specified exists, and I want to avoid this.
Like this:
SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = ??
UNION
SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = 0
AND NOT EXISTS (SELECT *
FROM table
WHERE EMPLOYEE_ID = ?? AND DTL_ID = ??)
You will of course have to fill in the ?? with the proper number.
If DTL_ID is always 0 or positive:
SELECT TOP 1 * FROM table
where EmployeeID = #EmployeeID and DTL_ID in (#DTL_ID,0)
order by DTL_ID desc
If you're working across multiple employees in a single query, etc, then you might want to use ROW_NUMBER() if your version of SQL supports it.
Use ISNULL(DTL_ID, 0) in your final SELECT query
SELECT E1.EMPLOYEE_ID, ISNULL(E2.DTL_ID, 0), E1.COLUMN_A, E1.COLUMN_B EMPLIYEES AS E1
LEFT JOIN EMPLIYEES AS E2
ON E1.EMPLOYEE_ID = E2.EMPLOYEE_ID AND E2.DTL_ID = 42
You can use top and union, e.g.:
declare #t table(id int, value int, c char)
insert #t values (1,0,'a'), (1,1,'b'), (1,2,'c')
declare #id int = 1;
declare #value int = 2;
select top(1) *
from
(
select *
from #t t
where t.value = #value and t.id = #id
union all
select *
from #t t
where t.value = 0
)a
order by a.value desc
If #value = 2 than query returns 1 2 c. If #value = 3 than query returns 1 0 a.
SELECT MAX(DTL_ID) ...
WHERE DTL_ID IN (#DTL_ID, 0)

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.

Can I check that two sub query return the same result without using stored procedure?

I have a table like this:
ObjId OtherObjId active (bool)
1 5 0
1 7 1
1 9 0
2 6 0
...
...
...
54 5 0
54 7 1
54 9 0
This two queries return an identical result:
select OtherObj2,active from MyTable where ObjId1 = 1;
select OtherObj2,active from MyTable where ObjId1 = 54;
I would like to run a single query that return return true if the two query result are identical or false if they are not.
The table is a configuration table and I want to test easily if two object have the same configuration. I can perform the check using a store procedure, however I would like to avoid to use it.
I cannot think a way to check it using a query, I am wondering if it is possible.
Any hints?
Thanks for your help.
Don't know if your DBMS supports except but if it does you can use this.
select OtherObjId, active
from MyTable
where ObjId = 1
except
select OtherObjId, active
from MyTable
where ObjId = 54
you could use minus
(select OtherObj2,active from MyTable where ObjId1 = 1
minus
select OtherObj2,active from MyTable where ObjId1 = 54
)
union
(select OtherObj2,active from MyTable where ObjId1 = 54
minus
select OtherObj2,active from MyTable where ObjId1 = 1
)
returns no rows if the result is the same.
(You need both minuses to see if query1 has more rows than query2 or if query2 has more rows than query1)
If your database supports set operations, use EXCEPT (AKA MINUS):
select OtherObj2,active from MyTable where ObjId1 = 1
EXCEPT
select OtherObj2,active from MyTable where ObjId1 = 54
This will result in an empty table if both are identical.
You could try something like this. If it returns any records, the query results were not identical. If it returns 0 records, there were no mismatches.
select
OtherObjId,
Active
from
MyTable
where
ObjId in (1, 54)
group by
OtherObjId,
Active
having COUNT(*) < 2

force a ceiling to count(*) in sql query

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

Check that all rows match a given criterion

requestId Consultantid statusid
1 2 10
2 2 10
3 2 10
I want to check if every row has a statusid of 10.
if (every row has a statusid of 10) then
-----do this
endif;
I'm a bit rusty on PL-SQL, but something like this would work in T-SQL:
if not exists (select * from your_table where statusid <> 10) then
-- whatever
end
Edit:
Ok, apparantly in PL-SQL, you need to do something like this:
DECLARE
notallten INTEGER;
BEGIN
SELECT COUNT(*) INTO notallten
FROM your_table
WHERE statusid <> 10
AND ROWNUM = 1;
IF notallten = 0 THEN
-- Do something
END IF;
END;
I don't have an Oracle server to test on though.
declare
v_exists_status_10 number(1);
...
begin
...
-- v_exists_status_10 = 0 if no such row exist, 1 if at least one does
select count(*)
into v_exists_status_10
from dual
where exists
(select * from your_table where statusid <> 10);
if v_exists_status_10 > 0 then
...
Note that you could also do a dumb COUNT() into a variable, but it could be massively inefficient compared to EXISTS. With a COUNT() you'd have to scan all the records, whereas with an EXISTS as soon as it hits a statusid = 10 it can stop scanning.
Simpler solution, that accounts for NULLs in statusid:
for r in (
select 1 dummy
from your_table
where (statusid != 10 or statusid is null)
and rownum = 1) loop
-----do this
end loop;