Searching in SQL based on values in 2 columns - sql

I currently have 2 columns for my database and I'm trying to return all values in column 1 that don't contain a certain value in column two:
ex: Column 1 has 9 digit random value, sometimes repeated. There are 4 different options for column 2; P1, P2, P3, P4.
I'm trying to only display values in column 1 that don't have a value of P4 in column 2. If they don't have a P4, then I want them all to be displayed, but once a Column 1 value is associated with P4, I don't want any of the column 1 values displayed. This process will continue through all column 1 values until the only values displayed in column 1 are values that do not have a P4 column 2 value associated with them.

You mean something like this?
SELECT *
FROM YOUR_TABLE
WHERE COLUMN1 NOT IN (
SELECT COLUMN1
FROM YOUR_TABLE
WHERE COLUMN2 = 'P4'
)

Wouldn't this just be
SELECT column1 FROM <table> WHERE column2 != 'P4'

This is an example of a query where you are looking at sets within sets -- that is, sets of column2 within values of column1. I prefer using group by and having for these queries:
select column1
from t
group by column1
having sum(case when column2 = 'P4' then 1 else 0 end) = 0
To get all the values, you would join back to the original table:
select t.*
from t join
(select column1
from t
group by column1
having sum(case when column2 = 'P4' then 1 else 0 end) = 0
) c1
on t.column1 = c1.column1

Related

Excluding a value when null is present in the column

I want to filter the table without the row c
column 1
column 2
a
100
b
200
c
50
null
200
Desired output
column 1
column 2
a
100
b
200
null
200
I tried
select *
from table
where column1 <> 'c'
But since I can compare with null, I'm getting the wrong output. How do I deal with this?
You need to handle the null as follows:
select * from table where column1 <> 'c' or column1 is null
Or you can use the coalesce function as follows:
select * from table where coalesce(column1,'cc') <> 'c'
Coalesce will replace the null value in column1 with the value provided as the second argument. I have used the value which is not equal to 'c' so records with column1 as null will pass this condition
ANSI SQL, DISTINCT predicate.
select *
from table
where column1 is distinct from 'c'
However, not supported by all dbms products.

SQL query for entries not spanning multiple rows

Say I have an oracle table that looks like this:
So, a sample can have 2 rows, one where test_value == value1 and one where test_value == value2, or one of them can be missing.
If I want to query for all the samples that have a value1 row but NOT a value2 row (i.e., all samples with a missing value2 row), how would I do that?
(I.e., in my example, I would expect to find sample2.)
Use not exists:
select *
from t
where t.test_value = 'value1' and
not exists(select 1 form t t2 where t2.sample = t.sample and t2.test_value = 'value2');
If you just want the samples and not the complete rows, then aggregation can also be used:
select sample
from t
where test_value in ('value_1', 'value_2')
group by sample
having min(test_value) = max(test_value) and
max(test_value) = 'value1';
Actually, for your particular strings, that can be simplified to:
having max(test_value) = 'value1'
try this, it detects the cases of samples which has only 1 value, and then checks that this value is value1.
SELECT SAMPLE
FROM
(
SELECT SAMPLE, SUM(CASE WHEN TEST_VALUE = 'value1' THEN 1 ELSE 0 END) AS IS_TEST_VALUE1
FROM tbl
GROUP BY SAMPLE
HAVING COUNT(*) = 1
) AS X
WHERE IS_TEST_VALUE1 = 1

Merging two columns but only unique combinations

I have two columns, each with identification numbers that have been brought in from different datasheets.
I want to combine this into one column with both identification numbers if they are different, but only one of the identification numbers if they are the same.
I'm using SELECT DISTINCT CONCAT(column 1, column 2) AS column 3 to combine the columns, but can not filter out UNIQUE combinations.
When I try WHERE column 1 <> column 2, I get an error message.
Any suggestions?
You can use CASE WHEN to test for conditions:
SELECT DISTINCT CASE WHEN column1 = column2 THEN column1
ELSE CONCAT(column1, column2)
END AS column3
FROM table1
try this using IIF or CASE and CONCAT
select
distinct
iif(col1<>col2,concat(col1,col2),col1) [myid]
from mytable
or
select
distinct
case when col1<>col2 then
concat(col1,col2)
else col1 end [myid]
from mytable
You should do something like:
SELECT DISTINCT CASE WHEN column1 = column2 THEN column1
ELSE column1 + '|' + column2
END AS combinedColumn
FROM table1
Consider the following chart:
column1 column2 column1+column2 column1+'|'+column2
12 34 1234 12|34
123 4 1234 123|4
1234 1234 1234 1234
Also, column1+column2 loses some information - what the original parts were.

How to get count values for multiple values in one column

My data is like this
Name Values
A Val1
A Val1
A Val2
A Val2
A Val2
B Val1
B Val2
I want to ouput my data is this way
Name Val1Count Val2Count
A 2 3
B 1 1
I can get the Name and count(*) for Val1 with this query.
select [Name],count(*) FROM [table1]
where [values]='Val1'
group by [Name]
But I am not sure how to get the count(*) for val2 in the same row.
I tried doing this, but looks like this is not supported
select [name],#val1count= (above query for val1), #val2count = (above query for val2)
Please help. Thanks for looking.
This is called pivoting. Some databases provide a PIVOT function. However, you can also do this manually.
SELECT [Name],
SUM ( CASE WHEN [Values]='VAL1' THEN 1 ELSE 0 END ) AS Val1Count,
SUM ( CASE WHEN [Values]='VAL2' THEN 1 ELSE 0 END ) AS Val2Count
FROM [table1]
GROUP BY [Name]
Explanation:
The CASE WHEN ... END gives each row a "boolean" value for whether or not the row matches your condition.
The SUM ( ... ) counts the number of rows which returned "true" (or 1).
The GROUP BY [Name] consolidates the rows down to one row per distinct name.
If you add conditions to a WHERE clause, the CASE WHEN will only see the rows matching your WHERE conditions.

Can I get the minimum of 2 columns which is greater than a given value using only one scan of a table

This is my example data (there are no indexes and I do not want to create any):
CREATE TABLE tblTest ( a INT , b INT );
INSERT INTO tblTest ( a, b ) VALUES
( 1 , 2 ),
( 5 , 1 ),
( 1 , 4 ),
( 3 , 2 )
I want the minimum value in of both column a and column b which is greater then a given value. E.g. if the given value is 3 then I want 4 to be returned.
This is my current solution:
SELECT MIN (subMin) FROM
(
SELECT MIN (a) as subMin FROM tblTest
WHERE a > 3 -- Returns 5
UNION
SELECT MIN (b) as subMin FROM tblTest
WHERE b > 3 -- Returns 4
)
This searches the table twice - once to get min(a) once to get min(b).
I believe it should be faster to do this with just one pass. Is this possible?
You want to use conditional aggregatino for this:
select min(case when a > 3 then a end) as minA,
min(case when b > 3 then b end) as minB
from tblTest;
To get the minimum of both values, you can use a SQLite extension, which handles multiple values for min():
select min(min(case when a > 3 then a end),
min(case when b > 3 then b end)
)
from tblTest
The only issue is that the min will return NULL if either argument is NULL. You can fix this by doing:
select coalesce(min(min(case when a > 3 then a end),
min(case when b > 3 then b end)
),
min(case when a > 3 then a end),
min(case when b > 3 then b end)
)
from tblTest
This version will return the minimum value, subject to your conditions. If one of the conditions has no rows, it will still return the minimum of the other value.
From the top of my head, you could modify the table and add a min value column to store the minimum value of the two columns. then query that column.
Or you can do this:
select min(val)
from
(
select min(col1, col2) as val
from table1
)
where
val > 3
The outer SELECT, queries the memory, not the table itself.
Check SQL Fiddle