Get opposite of a query's results Access 2016 - sql

I'm trying to create an query that displays the opposite of another query (just like a boolean NOT).
This is the first query:
SELECT RoomNumber, StructureNumber
FROM TimeTables
WHERE HourNumber = 1 AND DayNumber = 1
I need to get all the rows that doesn't exists in that query's results.
At the first time I tried to subtract the full table from the first query but I could not do it because there is no "EXCEPT" in Access and
also because I need to subtract between four columns (there are two primary key columns in that table)
this is my first try that didn't work:
SELECT RoomNumber, StructureNumber
FROM TimeTables
EXCEPT
SELECT RoomNumber, StructureNumber
FROM TimeTables
WHERE HourNumber = 1 AND DayNumber = 1
At the second time I try to pull the result that dosn't exists in the first query but also didn't work:
SELECT RoomNumber, StructureNumber
FROM TimeTables
WHERE NOT EXISTS(
SELECT RoomNumber, StructureNumber
FROM TimeTables
WHERE HourNumber = 1 AND DayNumber = 1)
I've searched for solutions at the internet and found some things that similar to my problem but none of them worked for me.

NOT EXISTS requires reference from the outer query which you haven't supply
So, your NOT EXISTS should be :
SELECT t.*
FROM TimeTables t
WHERE NOT EXISTS (SELECT 1
FROM TimeTables t1
WHERE t1.RoomNumber = t.RoomNumber and t1.StructureNumber = t.StructureNumber and
t1.HourNumber = 1 AND t1.DayNumber = 1
);
But, for instance where clause should enough

I think this does what you want:
SELECT RoomNumber, StructureNumber
FROM TimeTables
GROUP BY RoomNumber, StructureNumber
HAVING SUM(IIF(HourNumber = 1 AND DayNumber = 1, 1, 0)) = 0;
The HAVING clause counts the number of rows (for each RoomNumber/StructureNumber combination) that match your specified conditions. The = 0 means that there are no such rows.

Simply correlate the NOT EXISTS subquery to main query, facilitated using table aliases, t and sub:
SELECT t.*
FROM TimeTables t
WHERE NOT EXISTS
(SELECT 1
FROM TimeTables sub
WHERE sub.HourNumber = 1 AND sub.DayNumber = 1
AND sub.RoomNumber = t.RoomNumber
AND sub.StructureNumber = t.StructureNumber)
But simply run a WHERE clause reversing the logic:
SELECT t.*
FROM TimeTables t
WHERE t.HourNumber <> 1 OR t.DayNumber <> 1

Related

SQL Select row depending on values in different columns

I've already found so many answers here but now I can't seem to find any to my specific problem.
I can't figure out how to select a value from a row depending on the value in different columns
with the below table, I want to achieve the following results.
in case the value in column stdvpuni = 1 then return values / contents from this row for the article (column art).
in case the value in column stdvpuni = 0 then return values / contents from the row where STDUNIABG = 1 for this article (column art).
You seem to want one row part art, based on the content of other rows. That suggests using row_number():
select t.*
from (select t.*,
row_number() over (partition by art order by stdvpuni desc, STDUNIABG desc) as seqnum
from t
) t
where seqnum = 1;
You don't specify what to do if neither column is 1. You might want a where clause (where 1 in (stdvpuni, STDUNIABG)) or another condition in the order by.
I do not know what values / contents is, but I suppose that's easy for you to figure out. So, I will focus on the way to select this:
SELECT
CASE
WHEN current.stdvpuni = 1 THEN 'values / contents of current row'
ELSE 'values / contents of other row'
END
FROM yourtable current
JOIN yourtable other
ON other.stdvpuni = 1;
Use your conditions with NOT EXISTS in the WHERE clause:
SELECT t1.*
FROM tablename t1
WHERE t1.STDVPUNI = 1
OR (
t1.STDVPUNI = 0 AND t1.STDUNIABG = 1
AND NOT EXISTS (SELECT 1 FROM tablename t2 WHERE t2.ART = t1.ART AND t2.STDVPUNI = 1)
);

Find the Row which contain only row with zero and One for the Particular data

I have data where group will one row as zero and one and for the same data value will give one and two.
I have tried with below code .which seems to be not working
select *
from (select livecasnum, flag,
DENSE_RANK()over (partition by livecasnum order by flag) as Ranks
from TblcaseFlag
group by livecasnum, flag
) b
group by livecasnum,flag,Ranks
having count(flag + Ranks) = 1 and flag <> 1
I need only like data one row which having only zero and one ex: 99149
Why not use not exists instead :
select tf.*
from TblcaseFlag tf
where tf.flag = 0 and
not exists (select 1
from TblcaseFlag tf1
where tf.livecasnum = tf1.livecasnum and
tf1.flag = 1
);

Filter if values provided otherwise return everything

Say I have a table t with 2 columns:
a int
b int
I can do a query such as:
select b
from t
where b > a
and a in(1,2,3)
order by b
where 1,2,3 is provided from the outside.
Obviously, the query can return no rows. In that case, I'd like to select everything as if the query did not have the and a in(1,2,3) part. That is, I'd like:
if exists (
select b
from t
where b > a
and a in(1,2,3)
)
select b
from t
where b > a
and a in(1,2,3)
order by b
else
select b
from t
where b > a
order by b
Is there a way to do this:
Without running two queries (one for exists, the other one the actual query)
That is less verbose than repeating queries (real queries are quite long, so DRY and all that stuff)
Using NOT EXISTS with a Sub Query to Determine if condition exists
SELECT b
FROM
t
WHERE
b > a
AND (
NOT EXISTS (SELECT 1 FROM #Table WHERE a IN (1,2,3))
OR a IN (1,2,3)
)
ORDER BY
b
The reason this works is because if the condition exists then the OR statement will include the rows and if the condition does not exist then the NOT EXISTS will include ALL rows.
Or With Common Table Expression and window Function with Conditional Aggregation.
WITH cte AS (
SELECT
b
,CASE WHEN a IN (1,2,3) THEN 1 ELSE 0 END as MeetsCondition
,COUNT(CASE WHEN a IN (1,2,3) THEN a END) OVER () as ConditionCount
FROM
t
)
SELECT
b
FROM
cte
WHERE
(ConditionCount > 0 AND MeetsCondition = 1)
OR (ConditionCount = 0)
ORDER BY
b
I find it a bit "ugly". Maybe it would be better to materialize output from your query within a temp table and then based on count from temp table perform first or second query (this limits accessing the original table from 3 times to 2 and you will be able to add some flag for qualifying rows for your condition not to repeat it). Other than that, read below . . .
Though, bear in mind that EXISTS query should execute pretty fast. It stops whether it finds any row that satisfies the condition.
You could achieve this using UNION ALL to combine resultset from constrained query and full query without constraint on a column and then decide what to show depending on output from first query using CASE statement.
How CASE statement works: when any row from constrained part of your query is found, return resultset from constrainted query else return everything omitting the constraint.
If your database supports using CTE use this solution:
with tmp_data as (
select *
from (
select 'constraint' as type, b
from t
where b > a
and a in (1,2,3) -- here goes your constraint
union all
select 'full query' as type, b
from t
where b > a
) foo
)
SELECT b
FROM tmp_data
WHERE
CASE WHEN (select count(*) from tmp_data where type = 'constraint') > 0
THEN type = 'constraint'
ELSE type = 'full query'
END
;

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

Adjust SQL Query to force a record to appear first?

How can the below query be adjusted to return always the member with MemberID = 'xxx' as the first row
SELECT * FROM Members
select * from Members
order by case when MemberID = XXX then 0 else 1 end
This should work and it will also allow you to order the remaining items by MemberID (Assuming xxx=12 in this example)
SELECT *
FROM Members
ORDER BY CASE WHEN MemberID=12 THEN NULL ELSE isnull(MemberID,0) END
If the memberID column can't contain nulls, you can get away with this which might perform slightly better.
SELECT *
FROM Members
ORDER BY CASE WHEN MemberID=12 THEN NULL ELSE MemberID END
SELECT
CASE WHEN MemberID = 'xxx' AS 1 ELSE 0 END CASE AS magic,
*
FROM Members
ORDER BY magic DESC
The syntax might vary depending on yr db, but I hope you get the idea.
SELECT * FROM `Members` WHERE `MemberID` = '[ID]' LIMIT 1 UNION SELECT * FROM `Members`
This should work. Tested on my database instance. Chosen ID is always first.
A more robust solution, if you have more than one record that has to be floated to the top, or if you have a specific order for multiple records, is to add a ResultsOrder column to your table, or even another table MemberOrder(memberid, resultorder). Fill resultorder with big numbers and ...
Select m.*
From Members m
Left Join MemberOrder mo on m.MemberID=mo.MemberID
Order by coalesce(mo.resultorder, 0) DESC
try this:
SELECT * FROM Members
ORDER BY IF(x.MemberId = XXX, -1, ABS(x.MemberId))