SQL where column equals Val and equals Val2 - sql

If you have a table as per bellow:
Col1 Col2
1 1
2 1
3 1
1 2
3 2
2 3
is there a way to write a SQL query where (Col2 =1 and Col2=2) and the result is:
Col1
1
3

You could do this using intersect. Note that this wouldn't work in MySQL.
select col1 from tablename where col2 = 1
intersect
select col1 from tablename where col2 = 2

You can use HAVING with CASE WHEN:
SELECT Col1
FROM your_table
GROUP BY Col1
HAVING SUM(CASE WHEN Col2 = 1 THEN 1 END) > 0
AND SUM(CASE WHEN Col2 = 2 THEN 1 END) > 0;
LiveDemo
With MySQL you can write:
SELECT Col1
FROM your_table
GROUP BY Col1
HAVING SUM(Col2 = 1) > 0
AND SUM(Col2 = 2) > 0;

Self join version:
select distinct t1.col1
from (select col1 from tablename where col2 = 1) t1
join (select col1 from tablename where col2 = 2) t2 on t1.col1 = t2.col1

Related

How to create a pivot table where columns and rows are the same in Snowflake SQL?

I have a table like
col1 | col2 | col3 | col4 | col5
id1 | 1 0 0 1 0
id2 | 1 1 0 0 0
id3 | 0 1 0 1 0
id4 | 0 0 1 0 1
id5 | 1 0 1 0 0
id6 | 0 0 0 1 0
.
.
.
idN
How would I create a query such that I get a table like
col1 | col2 | col3 | col4 | col5
col1 | 3 1 1 1 0
col2 | 1 2 0 1 0
col3 | 1 1 2 0 1
col4 | 1 1 1 2 0
col5 | 0 0 1 0 1
where each entry in the result is the number of times that some value of 1 in one column occurred with another column that had a value of 1?
I can get the diagonal values by doing the following:
SELECT
sum(col1), sum(col2), sum(col3), sum(col4), sum(col5)
FROM (
SELECT
col1, col2, col3, col4, col5, col1 + col2 + col3 + col4 + col5 ) AS total
FROM (
SELECT
ROW_NUMBER()OVER(PARTITION BY id ORDER BY date) row_num, *
FROM (
SELECT DISTINCT(id), date, col1, col2, col3, col4, col5
FROM db.schema.table)
)
WHERE row_num = 1 AND total <= 1
ORDER BY total DESC);
I assume that I have to do some kind of pivot or various union all's but I can't seem to figure it out.
I think I would approach this by unpivoting the data and re-aggregating. The following gets the pairs and counts:
with u as (
select t.id, v.col
from t cross join lateral
(values ('col1', col1),
('col2', col2),
('col3', col3),
('col4', col4),
('col5', col5)
) v(col, val)
where val = 1
)
select u1.col, u2.col, count(*)
from u u1 join
u u2
on u1.id = u2.id
group by u1.col, u2.col;
This seems good enough for me, but you can use conditional aggregation:
select u1.col,
sum(case when u2.col = 'col1' then 1 else 0 end) as col1,
sum(case when u2.col = 'col2' then 1 else 0 end) as col2,
sum(case when u2.col = 'col3' then 1 else 0 end) as col3,
sum(case when u2.col = 'col4' then 1 else 0 end) as col4,
sum(case when u2.col = 'col5' then 1 else 0 end) as col5
from u u1 join
u u2
on u1.id = u2.id
group by u1.col;
Here is one approach that showcases one of Snowflake's powerful semi-structured functions (namely, OBJECT_CONSTRUCT(*)) and also exploits two meta-attributes (SEQ and KEY) that are returned by the FLATTEN function so that there is no need for a unique business key on the original (source) table:
WITH CTE_ROW AS (
SELECT OBJECT_CONSTRUCT(*) AS COL_DICT
FROM T
)
,CTE_ROW_COL AS (
SELECT F.SEQ - 1 AS ROW_OFFSET
,F.KEY AS COL_NAME
,COL_DICT[F.KEY]::INTEGER AS VAL
FROM CTE_ROW R
,LATERAL FLATTEN(R.COL_DICT) F
)
,CTE_CALC AS (
SELECT RC1.COL_NAME AS COL_NAME_1
,RC2.COL_NAME AS COL_NAME_2
,COUNT(*) AS COUNT_VAL
FROM CTE_ROW_COL RC1
JOIN CTE_ROW_COL RC2
ON RC2.ROW_OFFSET = RC1.ROW_OFFSET
AND RC2.VAL = 1
WHERE RC1.VAL = 1
GROUP BY RC1.COL_NAME
,RC2.COL_NAME
)
SELECT COL_NAME_1 AS COL_NAME
,SUM(IFF(COL_NAME_2='COL1', COUNT_VAL, 0)) AS COL1
,SUM(IFF(COL_NAME_2='COL2', COUNT_VAL, 0)) AS COL2
,SUM(IFF(COL_NAME_2='COL3', COUNT_VAL, 0)) AS COL3
,SUM(IFF(COL_NAME_2='COL4', COUNT_VAL, 0)) AS COL4
,SUM(IFF(COL_NAME_2='COL5', COUNT_VAL, 0)) AS COL5
FROM CTE_CALC
GROUP BY COL_NAME_1
ORDER BY COL_NAME_1
;

Count per category

have a table as below -
COL1 | COL2 | COL3
1 1 1
1 1 2
1 2 0
1 2 1
2 3 1
2 3 2
2 4 0
2 4 1
3 1 0
3 2 0
.
.
.
I want to select COL1 where all COL2 have sum(COL3) is > 0. If I am sure there are 20 distinct values in COL2, Then how can i pull all COL1 values that have all 20 COL2 filled with COL3 > 0. So the end result should be
COL1 | COL2 | COL3
1 1 3
1 2 1
2 3 3
2 4 1
I have tried a lot of ways to do this but no success.
Just use group by and having.
select col1,col2,sum(col3)
from tbl
group by col1,col2
having sum(col3)>0
select t1.*
from yourTable t1
inner join
(
select t.col1
from
(
select col1, col2, sum(col3) as col_sum
from yourTable
group by col1, col2
) t
group by t.col1
having sum(case when t.col_sum = 0 then 1 else 0 end) = 0
) t2
on t1.col1 = t2.col1
I use a CTE and a Group by with a where condition
;WITH CTE as (
select COL1,COL2,SUM(COL3) as COL3 FROM table1
Group By
COL1,COL2
)
select * from CTE
where COL3>0
Just group col2 and check if it's bigger then 0
select col1,col2,sum(col3)
from tbl
group by col2
having sum(col3)>0
http://sqlfiddle.com/#!9/537f8c/1
See if the below gives you the result that you are after. It is selecting the col1, col2 and a sum of col3 from a derived(?) table that is excluding the col3's that are 0:
select col1, col2, sum(col3)
from
(
select col1, col2, col3 from tbl where col3 <> 0
) as ds
group by col3

selection based on certain condition

select col1, col2, col3 from tab1
rownum col1 col2 col3
1 1 10 A
2 1 15 B
3 1 0 A
4 1 0 C
5 2 0 B
6 3 20 C
7 3 0 D
8 4 10 B
9 5 0 A
10 5 0 B
Output required is
col1 col2 col3
1 10 A
1 15 B
2 0 B
3 20 C
4 10 B
5 0 A
5 0 B
col1 and col2 are my lookup/joining columns columns, if col2 is having "non zero" data then I need to ignore/filter record with 0 (in above example I need to filter record rownum 3 4 and 7) If col2 is not having any data other than "non zero" in that case only select record with 0 (in above example col1 with value 1 and 5).
I m trying to write sql for this. Hope I have mentioned requirement clearly, please let me know if you need anything more from my side. Seem to have gone blank in this case.
Database - Oracle 10g
SELECT col1,
col2,
col3
FROM (SELECT col1,
col2,
col3,
sum(col2) OVER (PARTITION BY col1) sum_col2
FROM tab1)
WHERE ( ( sum_col2 <> 0
AND col2 <> 0)
OR sum_col2 = 0)
If col2 can be negative and the requirement is that the sum of col2 has "non-zero" data then the above is OK, however, if it is the requirement that any col2 value has "non-zero" data then it should be changed to:
SELECT col1,
col2,
col3
FROM (SELECT col1,
col2,
col3,
sum(abs(col2)) OVER (PARTITION BY col1) sum_col2
FROM tab1)
WHERE ( ( sum_col2 <> 0
AND col2 <> 0)
OR sum_col2 = 0)
SELECT t1.*
FROM tab1 t1
JOIN (SELECT "col1", MAX("col2") AS max2
FROM tab1
GROUP BY "col1") t2
ON t1."col1" = t2."col1"
WHERE ((max2 = 0 AND "col2" = 0)
OR
(max2 != 0 AND "col2" != 0))
ORDER BY "rownum"
DEMO

SQL assigning a value after testing against multiple columns

I have two columns:
INPUT
col1 col2
1 0
1 0
1 0
2 1
2 0
3 0
3 0
3 1
3 1
Let's suppose col1 holds some entity ID number, which is repeated. I'm testing whether this entity ID contains value 1 in col2. So if entity ID has 1 in corresponding col2 then I create another col3 with "NO"/"YES" values or just "0"/"1" accrodingly.
OUTPUT
col1 col3
1 NO
2 YES
3 YES
SELECT Col1, MAX(CASE WHEN col2 = 1 THEN 1 ELSE 0 END) Col3
FROM YourTable
GROUP BY Col1
UPDATED
Well, since the query above doesn't work for you, you can try the following:
SELECT Col1, MAX(Col3) Col3
FROM ( SELECT Col1,
CASE WHEN col2 = 1 THEN 1 ELSE 0 END AS Col3
FROM YourTable) A
GROUP BY Col1
UPDATE table
SET
col3 = DECODE(col2, 1, 'YES', 'NO');
If you want to run this for a given entity id only:
UPDATE table
SET
col3 = DECODE(col2, 1, 'YES', 'NO')
WHERE
col1 = yourid;
If your column 3 does not exist, you'll have to create it before hand anyway:
ALTER TABLE table ADD (col3 NUMBER NOT NULL);
SELECT Col1,
CASE WHEN MAX(Col2) = 1 THEN 'YES' ELSE 'NO' END AS Col3
FROM TableName
GROUP BY Col1
SQLFiddle Demo
SELECT DISTINCT col1,
CASE WHEN EXISTS(SELECT * FROM MyTab WHERE col1 = M.col1 AND col2 = 1)
THEN 'Yes' ELSE 'No' AS col3 FROM MyTab M

problem with select

I have a table with rows with two columns
A 1
A 2
B 1
B 3
C 1
C 2
C 3
and I want to get from this only this ID(a,b or c) which has only 2 rows with value 1,2, so from this table I should get a, bacause b hasn't row with 2, and c has rows with 1 and b, but also has row with c..
What is the simplest way to get this row?
SELECT col1
FROM YourTable
GROUP BY col1
HAVING COUNT(DISTINCT col2) =2 AND MIN(col2) = 1 AND MAX(col2) = 2
Or another way extendible to more than 2 numbers
SELECT col1
FROM yourtable
GROUP BY col1
HAVING MIN(CASE
WHEN col2 IN ( 1, 2 ) THEN 1
ELSE 0
END) = 1
AND COUNT(DISTINCT col2) = 2
select t1.col1
from table as t1
left join table as t2 on (t1.col1 = t2.col1)
where t1.col2 = 1 and t2.col2 = 2;