Reputation: 7986
I was wondering if anyone can help me write some code for the following logic.
We have a table
----------------
id, lang, letter
----------------
1 1 E
1 1 E
1 1 E
1 1 E
2 2 F
Problem:
I need to select ALL the rows for which the following condition fails:
I know I can hard code it. Also i would like to do this in ONE query only.
Please help
Upvotes: 1
Views: 153
Reputation: 57023
The idea here is that there are three business rules that may be implemented as three distinct tuple constraints (i.e. not false for every row in the table):
id
and lang
must be equal (begging the question, why not make one a computed column?).
If letter
is 'E'
then lang
must be 1
(I assume there is a typo in your question where you said 'e'
instead of 'E'
).
If letter
is 'F'
then lang
must be 2
(I assume there is a typo in your question where you said 2
instead of 'F'
).
The constraints 'don't have anything to say' about any other data (e.g. when letter
is 'X'
) and will allow this to pass.
All three tuple constraints can be written in conjunctive normal form as a constraint validation query:
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 )
The data that violates the constraints can be simply shown (in pseudo relational algebra) as:
T MINUS (constraint validation query)
In SQL:
SELECT * FROM T
EXCEPT
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 )
It is good to be able to rewrite predicates in case one's query of choice runs like glue on one's DBMS of choice! The above may be rewritten as e.g.
SELECT * FROM T
WHERE NOT ( id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 ) )
Applying rewrite laws (De Morgan's and double-negative) e.g.
SELECT * FROM T
WHERE id <> lang
OR ( letter = 'E' AND lang <> 1 )
OR ( letter = 'F' AND lang <> 2 )
Logically speaking, this should be better for the optimizer because for the above to be a contradiction every disjunct member must be false (put another way, it only takes one OR'ed clause to be true for the data to be deemed 'bad'). In practice (in theory?), the optimizer should be able to perform such rewrites anyhow!
p.s. nulls are bad for logic -- avoid them!
Here's my test code with sample data:
WITH Nums AS ( SELECT *
FROM ( VALUES (0), (1), (2) ) AS T (c) ),
Chars AS ( SELECT *
FROM ( VALUES ('E'), ('F'), ('X') ) AS T (c) ),
T AS ( SELECT N1.c AS id, N2.c AS lang,
C1.c AS letter
FROM Nums AS N1, Nums AS N2, Chars AS C1 )
SELECT * FROM T
EXCEPT
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 );
Upvotes: -1
Reputation: 247670
I think this is what you want to exclude the records meeting that criteria:
create table #t
(
id int,
lang int,
letter varchar(1)
)
insert into #t values (1, 1, 'E')
insert into #t values (1, 1, 'E')
insert into #t values (1, 1, 'E')
insert into #t values (1, 1, 'E')
insert into #t values (2, 2, 'F')
insert into #t values (1, 1, 'G')
insert into #t values (1, 1, 'H')
insert into #t values (1, 1, 'I')
insert into #t values (1, 1, 'J')
insert into #t values (2, 2, '2')
SELECT *
FROM #t
WHERE NOT
(
id = lang
AND
(
(
lang = 1
AND letter = 'E'
)
OR
(
lang = 2
AND letter = '2'
)
)
)
drop table #t
to get the records with that, just remove the NOT
it:
SELECT *
FROM #t
WHERE
(
id = lang
AND
(
(
lang = 1
AND letter = 'E'
)
OR
(
lang = 2
AND letter = '2'
)
)
)
Upvotes: 0
Reputation: 17957
WHERE NOT
(
id = lang
AND
(
(lang = 1 AND letter = 'e')
OR (lang = 2 AND letter = '2')
)
)
Upvotes: 3
Reputation: 26058
select * from table
where id <> lang and
(lang<>1 and letter <> 'e' or
lang<>2 and letter <> '2')
assuming you mean you want all data where both of those conditions are false.
Upvotes: 1