HAVING clause: at least one of the ungrouped values is X - sql

Example table:
Col1 | Col2
A | Apple
A | Banana
B | Apple
C | Banana
Output:
A
I want to get all values of Col1 which have more than one entry and at least one with Banana.
I tried to use GROUP BY:
SELECT Col1
FROM Table
GROUP BY Col1
HAVING count(*) > 1
AND ??? some kind of ONEOF(Col2) = 'Banana'
How to rephrase the HAVING clause that my query works?

Use conditional aggregation:
SELECT Col1
FROM Table
GROUP BY Col1
HAVING COUNT(DISTINCT col2) > 1 AND
COUNT(CASE WHEN col2 = 'Banana' THEN 1 END) >= 1
You can conditionally check for Col1 groups having at least one 'Banana' value using COUNT with CASE expression inside it.
Please note that the first COUNT has to use DISTINCT, so that groups with at least two different Col1 values are detected. If by having more than one entry you mean also rows having the same Col2 values repeated more than one time, then you can skip DISTINCT.

SELECT Col1
FROM Table
GROUP BY Col1
HAVING count(*) > 1
AND Col1 in (select distinct Col1 from Table where Col2 = 'Banana');

Here is a simple approach:
SELECT Col1
FROM table
GROUP BY Col1
HAVING COUNT(DISTINCT CASE WHEN col2= 'Banana' THEN 1 ELSE 2 END) = 2

Try this,
declare #t table(Col1 varchar(20), Col2 varchar(20))
insert into #t values('A','Apple')
,('A','Banana'),('B','Apple'),('C','Banana')
select col1 from #t A
where exists
(select col1 from #t B where a.col1=b.col1 and b.Col2='Banana')
group by col1
having count(*)>1

Related

How can I use a COUNT(DISTINCT var) to return the count of unique values per group?

I need to return a count of unique values, but unique per group of the result set, not unique to the entire result set. For example I would like the following code:
SELECT col1 AS letters, count(DISTINCT col2) AS numbers
GROUP BY col1;
applied to this data:
col1 col2
a 5
a 5
a 6
b 1
b 2
b 6
To return this:
col1 col2
a 2
b 3
If the above code will not produce this, how can I accomplish this is T-SQL?
I hope this works for your solution, you need to use group by on col2 with count distinct of col2
SELECT
col1,
COUNT(DISTINCT col2)
FROM
count_unique_values_per_group
GROUP BY
col1
Try this:
SELECT DISTINCT col1
,dense_rank() over (partition by col1 order by col2 asc) + dense_rank() over (partition by col1 order by col2 desc) - 1
FROM my_table
Apply concat function to get the unique count. Hope this helps..
SELECT col1, count(distinct col1 + col2) FROM table_name group by col1;
or
SELECT col1, count(distinct concat(col1,col2)) FROM table_name group by col1;

Need two rows after join from single row based on two columns

I have a table1 with three columns and a table2 with single column.
If the value of first column is Y then I need a particular value from table 2 as a row in another table after join and if the second column is Y then I need a particular value from table 2 as another row in 3rd table after join. There is no common column in both the tables.
If two columns are in a row have Y as value then I need two rows in the final table after join. I'm using case right now for joining, but only one column is getting checked.
Can someone help me with this?
table1
--------------------
col1 col2 col3(pk)
--------------------
y n 123
y y 456
table2
--------------------
col1
--------------------
col1Y
col2Y
Expected output
table1
--------------------
col1 col2
--------------------
123 col1Y
456 col1Y
456 col2Y
select col3 as col1, 'col1y' as col2 from myTable where col1 = 'y'
union
select col3 as col1, 'col2y' as col2 from myTable where col2 = 'y'
--order by col1, col2;
SQLFiddle sample
you also can check how to transpose tables with pivot command
SQL transpose full table
We can unpivot and join to get the results you're looking for:
declare #table1 table (col1 char(1),col2 char(1),col3 int)
insert into #table1(col1,col2,col3) values
('y','n',123) ,
('y','y',456)
declare #table2 table (col1 char(5))
insert into #table2 (col1) values
('col1Y'),('col2Y')
select
u.col3 as col2,t2.col1 as col2
from
#table1 t1
unpivot
(cval for cname in (col1,col2)) u
cross apply
(select cname + cval as Complete) v
inner join
#table2 t2
on
v.complete = t2.col1
Result:
col1 col2
----------- -----
123 col1Y
456 col1Y
456 col2Y
But after the unpivot and cross apply, we didn't really need table2 at all (we could have just filtered down to rows where cval is Y). But for now I've included it in case I'm missing something or there's more to build up in the query.
Not sure if you need table2 but here is where you could do it with case statement.
SELECT col1, col2 from (
SELECT
CASE col1
WHEN 'y' THEN col3
ELSE 'null'
END AS col1,
CASE col1
WHEN 'y' THEN 'col1Y'
ELSE 'null'
END AS col2
from table1 as tbl1
union all
select
CASE col2
WHEN 'y' THEN col3
ELSE 'null'
END AS col1,
CASE col2
WHEN 'y' THEN 'col2Y'
ELSE 'null'
END AS col2
FROM table1 as tbl2) as tbl
where tbl.col1 <> 'null';
SQL Fiddle Sample

How to get min value from multiple columns for a row in SQL

I need to get to first (min) date from a set of 4 (or more) columns.
I tried
select min (col1, col2, col3) from tbl
which is obviouslly wrong.
let's say I have these 4 columns
col1 | col2 | col3 | col4
1/1/17 | 2/2/17 | | 3/3/17
... in this case what I want to get is the value in col1 (1/1/17). and Yes, these columns can include NULLs.
I am running this in dashDB
the columns are Date data type,
there is no ID nor Primary key column in this table,
and I need to do this for ALL rows in my query,
the columns are NOT in order. meaning that col1 does NOT have to be before col2 or it has to be null AND col2 does NOT have to be before col3 or it has to be NULL .. and so on
If your DB support least function, it is the best approach
select
least
(
nvl(col1,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col2,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col3,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col4,TO_DATE('2901-01-01','YYYY-MM-DD'))
)
from tbl
Edit: If all col(s) are null, then you can hardcode the output as null. The below query should work. I couldn't test it but this should work.
select
case when
least
(
nvl(col1,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col2,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col3,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col4,TO_DATE('2901-01-01','YYYY-MM-DD'))
)
= TO_DATE('2901-01-01','YYYY-MM-DD')
then null
else
least
(
nvl(col1,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col2,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col3,TO_DATE('2901-01-01','YYYY-MM-DD')),
nvl(col4,TO_DATE('2901-01-01','YYYY-MM-DD'))
)
end
as min_date
from tbl
If a id column in your table. Then
Query
select t.id, min(t.col) as min_col_value from(
select id, col1 as col from your_table
union all
select id, col2 as col from your_table
union all
select id, col3 as col from your_table
union all
select id, col4 as col from your_table
)t
group by t.id;
If you want the first date, then use coalesce():
select coalesce(col1, col2, col3, col4)
from t;
This returns the first non-NULL value (which is one way that I interpret the question). This will be the minimum date, if the dates are in order.
Select Id, CaseWhen (Col1 <= Col2 OR Col2 is null) And (Col1 <= Col3 OR Col3 is null) Then Col1 When (Col2 <= Col1 OR Col1 is null) And (Col2 <= Col3 OR Col3 is null) Then Col2 Else Col3 End As Min From YourTable
This is for 3 Column, Same way you can write for 4 - or more column.

How to use and "in" clause in "having" in HIVE?

I have my data in sometable like this:
col1 col2 col3
A B 3
A B 1
A B 2
C B 1
And I want to get all of the unique groups of col1 and col2 that contain certain rows of col3. Like, all groups of col1 and col2 that contain a "2".
I wanted to do something like this:
select col1, col2 from sometable
group by col1, col2
having col3=1 and col3=2
But I want it to only return groups that have an instance of both 1 and 2 in col3. so, the result after the query should return this:
col1 col2
A B
How do I express this in HIVE? THANK YOU.
I don't know why others deleted answers that where correct and then almost correct but I will put their's back up.
SELECT col1, col2, COUNT(DISTINCT col3)
FROM
sometable
WHERE
col3 IN (1,2)
GROUP BY col1, col2
HAVING
COUNT(DISTINCT col3) > 1
If you actually want to return all of the records that meet your criteria you need to do a sub select and join back to the main table to get them.
SELECT s.*
FROM
sometable s
INNER JOIN (
SELECT col1, col2, COUNT(DISTINCT col3)
FROM
sometable
WHERE
col3 IN (1,2)
GROUP BY col1, col2
HAVING
COUNT(DISTINCT col3) > 1
) t
ON s.Col1 = t.Col1
AND s.Col2 = t.Col2
AND s.col3 IN (1,2)
The gist of this is narrow/filter your rowset to the rows that you want to test col3 IN (1,2) then count the DISTINCT values of col3 to make sure both 1 and 2 exist and not just 1 & 1 or 2 & 2.
I think below mentioned query will be useful for your question.
select col1,col2
from Abc
group by col1,col2
having count(col1) >1 AND COUNT(COL2)>2

select all columns with one column has different value

In my table,some records have all column values are the same, except one. I need write a query to get those records. what's the best way to do it? the table is like this:
colA colB colC
a b c
a b d
a b e
What's the best way to get all records with all the columns? Thanks for everyone's help.
Assuming you know that column3 will always be different, to get the rows that have more than one value:
SELECT Col1, Col2
FROM Table t
GROUP BY Col1, Col2
HAVING COUNT(distinct col3) > 1
If you need all the values in the three columns, then you can join this back to the original table:
SELECT t.*
FROM table t join
(SELECT Col1, Col2
FROM Table t
GROUP BY Col1, Col2
HAVING COUNT(distinct col3) > 1
) cols
on t.col1 = cols.col1 and t.col2 = cols.col2
Just select those rows that have the different values:
SELECT col1, col2
FROM myTable
WHERE colWanted != knownValue
If this is not what you are looking for, please post examples of the data in the table and the wanted output.
How about something like
SELECT Col1, Col2
FROM Table
GROUP BY Col1, Col2
HAVING COUNT(*) = 1
This will give you Col1, Col2 that have unique data.
Assuming col3 has the difs
SELECT Col1, Col2
FROM Table
GROUP BY Col1, Col2
HAVING COUNT(*) > 1
OR TO SHOW ALL 3 COLS
SELECT Col1, Col2, Col3
FROM Table1
GROUP BY Col1, Col2, Col3
HAVING COUNT(Col3) > 1