Oracle: Get All Rows Except One - sql

I am stuck with a simple query. What i want is to get all rows except one Kindly have a look at the following data.
COL_A COL_B
B D
B (null)
B C
G D
G (null)
G C
I want to get all rows except but B C. Kindly have a look at the sqlfiddle
I have tried to get the rows by anding col_A <> 'B' and col_B <> 'C' but it's not anding the operation. Your help will be much appreciated.
Thanks

One possible solution. Maybe not the most elegant:
select req_for col_A, doc_typ col_B
from a
where (req_for IS NULL OR doc_typ IS NULL)
OR (req_for,doc_typ)
NOT IN (select 'B','C' from dual);

Try
where not(col_A = 'B' and col_B = 'C')
or
where col_A <> 'B' or col_B <> 'C'

Your problem is the NULL values. Here is a concise way of expressing this in Oracle:
where (col_A || col_B) <> 'BC'
Oracle treats NULL values as the empty string in string concatenation.

Ah, negatives. Always causing trouble. With a SQL query like this you have to think about what you want to INCLUDE, not what you want to EXCLUDE.
If you do where nvl(doc_typ,'NA') <> 'C' and nvl(req_for, 'NA') <> 'B';, you aren't including any rows with doc_type of C, and you aren't including any rows with req_for of B.
You want to do where nvl(doc_typ,'NA') <> 'C' or nvl(req_for, 'NA') <> 'B';. This way a doc_type of C will still be included, as long as its req_for isn't also B.

Could you not just remove the unwanted row:
select req_for col_A, doc_typ col_B from a
where NOT (NVL(doc_typ,'NA') = 'C' AND nvl(req_for,'NA') = 'B');

select req_for col_A, doc_typ col_B from a
where req_for||doc_typ != 'BC';
select req_for col_A, doc_typ col_B from a
where case when req_for = 'B' and doc_typ='C' then 0 else 1 end > 0

Related

PostgreSQL: using case to compare values between columns

I would like to compare two columns, A and B.
If Col A and Col B share the same value, I would like Col A to have a no value set.
If Col A and Col B do not share the same value, I would like Col A to keep the original value it has.
Below is what I attempted. However, it returns "true" for all entries in the case column - Col A (corrected).
select *,
case when 'Col A' = 'Col B'
then 'Col A' = null
else 'Col A' = 'Col A'
end as "Col A (corrected)"
from my_table
select
case
when col_a=col_b then null
else col_a
end as col_a_corrected
from my_table
Simply do
select *,
NULLIF(col_a, col_b)
from my_table
The NULLIF returns null if col_a = col_b, otherwise col_a is returned.
https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-NULLIF

SQL append column at the bottom of another column

What is the best way to append a column at the bottom of another column? So it would look something like this:
column_a column_b
a e
f k
c m
new_column
a
f
c
e
k
m
All i can really find is answers on how to merge two column into one and this is with CONCAT() but nothing about pasting two column ontop of each other.
If you want to keep the order, you could use something like this.
with col_a as (select 'a' as column_a union select 'f' union select 'c'),
col_b as (select 'e' as column_b union select 'k' union select 'm')
select 1 as num_order,
column_a
from col_a
union all
select 2 as num_order,
column_b
from col_b
order by num_order;
Yields:
1,a
1,c
1,f
2,e
2,k
2,m
If the order is irrelevant you can omit the num_order attribute.

Select using WHERE if any exist, else don't use WHERE

I want to select from a table where column = 'n'. If the result has 0 rows, I want to remove that conditional.
Some pseudo-sql might be:
SELECT * FROM MY_TABLE
WHERE COL_A = 1 AND COL_B = 'mystring'
ELSE
SELECT * FROM MY_TABLE
WHERE COL_A = 1;
I will only be using the first row in either result, so it would also be acceptable to somehow sort the result such that rows where COL_B = 'mystring' appear at the top.
If you do not have too many values for each col_a value, you can use:
select t.*
from t
where col_a = 1
order by (case when col_b = 'mystring' then 1 else 2 end);
Just use the first row in the result set.
Assuming this is MSSQL:
SELECT
*
FROM
MY_TABLE
CROSS JOIN
(
SELECT
COUNT(*) c
FROM
MY_TABLE
WHERE
COL_A = 1
AND
COL_B = 'mystring'
) MY_WHERE_COUNT
WHERE (
MY_WHERE_COUNT.c > 0 AND MY_TABLE.COL_A = 1 AND MY_TABLE.COL_B = 'mystring'
)
OR (
MY_WHERE_COUNT.c = 0 AND MY_TABLE.COL_A = 1
)

How can I acces the output from the first select statement

I have a table Like this
Col1 | Col2
-----------
a | d
b | e
c | a
Now I want to create an statement to get an output like this:
First| Second
-------------------
a | Amsterdamm
b | Berlin
c | Canada
...
So far I have this consturct what is not working
SELECT *
FROM(
SELECT DISTINCT
CASE
when Col1 IS NULL then 'NA'
else Col1
END
FROM Table1
UNION
SELECT DISTINCT
CASE
when Col2 IS NULL then 'NA'
else Col2
END
FROM Table1
) AS First
,
(
SELECT DISTINCT
when First= 'a' then 'Amsterdam'
when First= 'b' then 'Berlin'
when First= 'c' then 'Canada'
) AS Second
;
can you help me with that
Sorry I have to edit my question to be more specific.
Not as familiar with DB2... I'll lookup if it has a concat function in a sec... and it does.
SELECT First, case when first = 'a' then
concat('This is a ',first)
case when first = 'b' then
concat('To Be or not to ',first)
case else
concat('This is a ',first) end as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
WHERE first <> 'NA'
What this does is generate a single inline view called src with a column called first. If col1 or col2 of table are null then it substitutes NA for that value. It then concatenates first and the desired text excluding records with a first value of 'NA'
Or if you just create an inline table with the desired values and join in...
SELECT First, x.b as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
INNER JOIN (select a,b
from (values ('a', 'This is a'),
('b', 'To B or not to' ),
('c', 'I like cat whose name starts with')) as x(a,b)) X;
on X.a = src.first
WHERE first <> 'NA'
Personally I find the 2nd option easier to read. Though if you have meaning for a,b,c I would think you'd want that stored in a table somewhere for additional access. In code seems like a bad place to store data like this that could change.
Assuming you want
a this is a a
b this is a b
c this is a c
d this is a d
e this is a e
thanks to xQbert
I could solve this problem like this
SELECT FirstRow, concat
(
CASE FirstRow
WHEN 'AN' then 'amerstdam'
WHEN 'G' then 'berlin'
ELSE 'NA'
END, ''
) AS SecondRow
FROM(
Select coalesce (Col1, 'NA') as FirstRow
FROM Table1
UNION
Select coalesce (Col2, 'NA')
FROM Table1) SRC
WHERE FirstRow <> 'NA'
;

Where Clause 'drops' more rows than expected

I have a SQL Server 2008 R2 query that was returning "hypothetically" 100 rows. I'm actually working with 7k - 8k rows.
The Where clause is something like this:
Where Col_a = 'Y'
And Col_b = 'N'
And Col_c = 'X'
and 25 of the rows had 'P' in Col_d.
I added:
And Col_d = 'P'
and the query returned the expected 25 rows.
Then I changed to
And Col_d <> 'P'
I expected to get 75 rows but I got only 50.
I thought adding "And Col_d <> 'P'" would only restrict the rows in which there is a 'P' in Col_d.
Why is that not the case and how do I figure out what else is getting dropped when I say And Col_d <> 'P'?
As I said - I am actually working with larger numbers so it is not that easy to eyeball it.
I'd appreciate any help.
Thanks!
As stated in the comment, null is a special case when it comes to comparisons.
Assume the following data.
id someVal
----
0 null
1 1
2 2
With a query:
select id
from table
where someVal = 1
would return id 1
select id
from table
where someVal <> 1
would return id 2
select id
from table
where someVal is null
would return id 0
select id
from table
where someVal is not null
would return both ids 1 and 2.
If you wanted nulls to be "counted" as values in a = <> comparison, it needs to be cast to something like:
select id
from table
where isNull(someVal, -1) <> 1
returns 0 and 2
Or you can change your ANSI Null setting.
What I want to do is only exclude the rows that have 'P' in Col_d
So in your specific case, because you want to treat null in Col_D as a non P row, your query could look like this:
select *
from someTable
Where Col_a = 'Y'
And Col_b = 'N'
And Col_c = 'X'
And isNull(Col_D, 'someArbitraryValue') <> 'P'
You have to do the above, because as I pointed out throughout the answer and in the links null does not compare the same way as values. You need to make the null something that is not null, (accomplished with isNull(Col_D, 'someArbitraryValue')) or change ANSI NULL setting in order to compare it as equal or not equal to some value.
Or as #Andrew pointed out magic numbers are bad (someArbitraryValue), so you could instead do:
select *
from someTable
Where Col_a = 'Y'
And Col_b = 'N'
And Col_c = 'X'
And (Col_D <> 'P' OR Col_D is null)
Normally I would do the directly above query, I was doing it the other way to mostly point out the differences in null comparison vs a value.