Get column with two two rows having specific values - sql

I have a table that looks like this:
| col1 | col2 |
|------|------|
| a | 1 |
| a | 2 |
| a | 3 |
| b | 1 |
| b | 3 |
| c | 1 |
| c | 2 |
I need to find the value of col1 where two rows with the same col1 value exist that has a col2 value of 1 and 2
results would be:
| col1 |
|------|
| a |
| c |

You can filter the rows with the col2 values you want, then group by col1 and only take the groups with count = 2
select col1
from yourTable
where col2 in (1, 2)
group by col1
having count(distinct col2) = 2

Another solution would be
select col1
from your_table
group by col1
having sum(case when col2 = 1 then 1 else 0 end) > 0
and sum(case when col2 = 2 then 1 else 0 end) > 0

Related

postgres count distinct values from multiple column

I am trying to display all different values from 3 columns and the amount of them.
My table:
date | col1 | col2 | col3
-------------------------------
26...| a | a | b
25...| c | d | a
...
All 3 columns have the values a, b, c, d.
I would like to have something like this:
date | col | a | b | c | d
--------------------------------------
26.....| col1 | 1 | 0 | 0 | 0
26.....| col2 | 1 | 0 | 0 | 0
26.....| col3 | 0 | 1 | 0 | 0
25.....| col1 | 0 | 0 | 1 | 0
25.....| col2 | 0 | 0 | 0 | 1
Is there a way to do it?
Welcome to SO. Assuming that the possible values are fixed (a,b,c and d), an alternative is to create a row for each column and date in a CTE and in the outer query count them with a FILTER, e.g.
WITH j (date,col) AS (
SELECT date, unnest(array[col1,col2,col3])
FROM mytable
)
SELECT j.date, 'col'||j.col,
count(*) FILTER (WHERE col ='a'),
count(*) FILTER (WHERE col ='b'),
count(*) FILTER (WHERE col ='c'),
count(*) FILTER (WHERE col ='d')
FROM j
JOIN mytable t ON t.date = j.date
GROUP BY j.date,j.col
ORDER BY j.date,j.col;
Demo: db<>fiddle

Translate table values to text following a fixed pattern

We use software to store combinations of financial elements. Those elements are allowed in certain combinations. Exceptions of these combinations are SQL-like statements in the front-end, and are saved as numerical values in a database table like the following example:
+------+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 | Col5 |
+------+------+------+------+------+
| 1 | 2 | 4 | 5 | 1 |
+------+------+------+------+------+
| -1 | 2 | 6 | 4 | 5 |
+------+------+------+------+------+
| 1 | 2 | 5 | 7 | 1 |
+------+------+------+------+------+
I would like to translate those numerical values back to a SQL-statement like the following example:
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| Col1 | Col1Trans | Col2 | Col2Trans | Col3 | Col3Trans | Col4 | Col4Trans | Col5 | Col5Trans |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| 1 | ( | 2 | SELECT | 4 | CODE | 5 | LIKE | 1 | * |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| -1 | | 2 | SELECT | 6 | NUMBER | 4 | = | 5 | AND |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| 1 | ( | 2 | SELECT | 5 | TOOL | 7 | <> | 1 | * |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
The numerical values differ in each column so I can only imagine the use of a lot of case...when statements which I doubt will be efficiƫnt. I don't want to create tables to hold the translation values. Are there ways to do this with arrays?
Are there any code samples to easily loop through table/columns and translate the contents of it?
You can use below code and add more case statement as per the requirement.
SELECT Col1
,CASE
WHEN Col1 = 1 THEN '('
ELSE '' END AS Col1Trans
,Col2
,CASE
WHEN Col2 = 2 THEN 'SELECT'
END AS Col2Trans
,Col3
,CASE
WHEN Col3 = 4 THEN 'CODE'
WHEN Col3 = 6 THEN 'NUMBER'
WHEN Col3 = 5 THEN 'TOOL'
END AS Col3Trans
,Col4
,CASE
WHEN Col4 = 5 THEN 'LIKE'
WHEN Col4 = 4 THEN '='
WHEN Col4 = 7 THEN '<>'
END AS Col4Trans
,Col5
,CASE
WHEN Col5 = 1 THEN '*'
WHEN Col5 = 5 THEN 'AND'
END AS Col5Trans
The best way to avoid so many case when and decode and etc is to use with as clause as following:
With col1trans (value, translation) as
(Select 1, '(' from dual union all
Select -1, null from dual),
Col2trans (value, translation) as
(Select 2, 'SELECT' from dual)
..
... till col5trans
Select m.col1, t1.translation as col1trans,
.... till m.col5, t5.translation
From your_table m join col1trans t1 m.col1=t1.value
join col2trans t2 m.col2=t2.value
... till col5trans
Cheers!!

Fetch the column which has the Max value for a row in Hive

I have a scenario where i need to pick the greatest value in the row from three columns, there is a function called Greatest but it doesn't work in my version of Hive 0.13.
Please suggest better way to accomplish it.
Example table:
+---------+------+------+------+
| Col1 | Col2 | Col3 | Col4 |
+---------+------+------+------+
| Group A | 1 | 2 | 3 |
+---------+------+------+------+
| Group B | 4 | 5 | 1 |
+---------+------+------+------+
| Group C | 4 | 2 | 1 |
+---------+------+------+------+
expected Result:
+---------+------------+------------+
| Col1 | output_max | max_column |
+---------+------------+------------+
| Group A | 3 | Col4 |
+---------+------------+------------+
| Group B | 5 | col3 |
+---------+------------+------------+
| Group C | 4 | col2 |
+---------+------------+------------+
select col1
,tuple.col1 as output_max
,concat('Col',tuple.col2) as max_column
from (select Col1
,sort_array(array(struct(Col2,2),struct(Col3,3),struct(Col4,4)))[2] as tuple
from t
) t
;
sort_array(Array)
Sorts the input array in ascending order according to the natural ordering of the array elements and returns it
(as of version 0.9.0).
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
hive> select col1
> ,tuple.col1 as output_max
> ,concat('Col',tuple.col2) as max_column
>
> from (select Col1
> ,sort_array(array(struct(Col2,2),struct(Col3,3),struct(Col4,4)))[2] as tuple
> from t
> ) t
> ;
OK
Group A 3 Col4
Group B 5 Col3
Group C 4 Col2

SQL Count across columns

I know that this table structure is horrible and that I should look into database normalization, but this is what I have to work with at the moment.
I need to find the most common number across the columns where one of them has a specific id (in my example 3). Both columns will never have the same value.
Query
SELECT Col1, Col2 FROM scores WHERE Col1 = 3 OR Col2 = 3
Result
+------+------+
| Col1 | Col2 |
+------+------+
| 1 | 3 |
| 3 | 1 |
| 2 | 3 |
| 6 | 3 |
| 3 | 7 |
| 3 | 9 |
| 2 | 3 |
| 5 | 3 |
+------+------+
I'm hoping to get a result like this (I don't need count for 3 since it's the ID, but it can be included)
+-------+-------+
| Value | Count |
+-------+-------+
| 1 | 2 |
| 2 | 2 |
| 5 | 1 |
| 6 | 1 |
| 7 | 1 |
| 9 | 1 |
+-------+-------+
I've tried a few things such as UNION and nested SELECT but that doesn't seem to solve this thing.
Any suggestions?
If you want a count of the values where the OTHER column is 3, then a UNION would work like this:
SELECT value, theCount = COUNT(*)
FROM (
SELECT value = col1
FROM scores
WHERE col2 = 3
UNION ALL
SELECT col2
FROM scores
WHERE col1 = 3) T
GROUP BY value
ORDER BY value;
One way is using case:
SELECT
case Col1 when 3 then Col2 else Col1 end,
count(*)
FROM scores
WHERE Col1 = 3 OR Col2 = 3
Group by
case Col1 when 3 then Col2 else Col1 end;

SQL Check if ungroup column values match

I have a sql table with following values
| col1 | col2| source | values
| 1 | 2 | A | null
| 1 | 2 | B | 1.0
| 1 | 2 | C | null
| 1 | 4 | A | 2.0
| 1 | 4 | B | 2.0
| 1 | 4 | C | 2.0
| 1 | 5 | A | null
| 1 | 5 | B | null
| 1 | 5 | C | null
How can I get an output with a group by of col1 and col2 with a flag:
all values match for a group ( flag = 1)
all values are null ( flag = 2)
some values is null (flag = 3)
Output:
| col1 | col2| flag
| 1 | 2 | 3
| 1 | 4 | 1
| 1 | 5 | 2
Or: based on your updated question:
SELECT
col1,
col2,
SUM(CASE WHEN SomeConditionHere THEN 1 ELSE 0 END) AS Flag
FROM Table1
GROUP BY col1, col2;
SQL Fiddle Demo
This will give you:
| COL1 | COL2 | FLAG |
----------------------
| 1 | 2 | 2 |
| 1 | 4 | 0 |
| 1 | 5 | 3 |
Note that: I assumed that the flag is how many NULL values are in the VALUES column, so I used "Values" IS NULL instead of SomeConditionHere.
I couldn't understand how the flag should be computed in the expected results you posted. You have to use the predicate that define your flag instead of "Values" IS NULL.
Update:
Try this:
WITH Flags
AS
(
SELECT
col1, col2,
COUNT(*) ValuesCount,
SUM(CASE WHEN "Values" IS NULL THEN 1 ELSE 0 END) AS NULLValues
FROM Table1
GROUP BY col1, col2
)
SELECT
col1,
col2,
Flag = CASE WHEN ValuesCount = NULLValues THEN 2
WHEN NULLVALUES = 0
AND ValuesCount = (SELECT COUNT(*)
FROM Table1 t2
WHERE t1.col1 = t2.col1
AND t1.col2 = t2.col2) THEN 1
ELSE 3
END
FROM Flags t1;
Updated SQL Fiddle Demo
This will give you:
| COL1 | COL2 | FLAG |
----------------------
| 1 | 2 | 3 |
| 1 | 4 | 1 |
| 1 | 5 | 2 |
In SQLServer2005+
;WITH cte AS
(
SELECT col1, col2, [values],
COUNT(CASE WHEN [values] IS NULL THEN 1 END) OVER(PARTITION BY col1, col2) AS cntNULL,
COUNT(*) OVER(PARTITION BY col1, col2) AS cntCol
FROM dbo.test5
)
SELECT col1, col2, MAX(CASE WHEN cntNULL = 0 THEN 1
WHEN cntNULL = cntCol THEN 2
ELSE 3 END) AS flag
FROM cte
GROUP BY col1, col2
Demo on SQLFiddle
...And solution without CTE if you want more portable SQL:
select col1,
col2,
case
when DistinctValuesWithoutNulls = 1 and NullCount = 0 then 1
when DistinctValuesWithoutNulls = 0 then 2
when NullCount > 0 then 3
end flag
from
(
select col1,
col2,
count(distinct [values]) DistinctValuesWithoutNulls,
sum(case when [values] is null then 1 else 0 end) NullCount
from Table1
group by col1, col2
) tmp