Merge multiple columns into one column with multiple rows - sql

In PostgreSQL, how can I merge multiple columns into one column with multiple rows?
The columns are all boolean, so I want to:
Filter for true values only
Replace the true value (1) with the name of the column (A, B or C)
I have this table:
ID | A | B | C
1 0 1 0
2 1 1 0
3 0 0 1
4 1 0 1
5 1 0 0
6 0 1 1
I want to get this table:
ID | Letter
1 B
2 A
2 B
3 C
4 A
4 C
5 A
6 B
6 C

I think you need something like this:
SELECT ID, 'A' as Letter FROM table WHERE A=1
UNION ALL
SELECT ID, 'B' as Letter FROM table WHERE B=1
UNION ALL
SELECT ID, 'C'as Letter FROM table WHERE C=1
ORDER BY ID, Letter

SELECT ID,
(CASE
WHEN TABLE.A = 1 then 'A'
WHEN TABLE.B = 1 then 'B'
WHEN TABLE.C = 1 then 'C'
ELSE NULL END) AS LETTER
from TABLE

You may try this.
insert into t2 select id, 'A' from t1 where A=1;
insert into t2 select id, 'B' from t2 where B=1;
insert into t2 select id, 'C' from t3 where C=1;
If you care about the order, then you can do this.
insert into t3 select id, letter from t2 order by id, letter;

W/o UNION
You can use a single query to get the desired output.Real time example
select id
,regexp_split_to_table((
concat_ws(',', case
when a = 0
then null
else 'a'
end, case
when b = 0
then null
else 'b'
end, case
when c = 0
then null
else 'c'
end)
), ',') l
from c1;
regexp_split_to_table() & concat_ws()

Related

Select table adding columns with data depending on duplicates in other column

Imagine this data.
Id
Type
1
A
1
B
1
B
2
A
3
B
I want to select table and ad two columns turning it to this. How can i do it? (In teradata)
Id
Type
Id with both A+B
Id with only A
1
A
1
0
1
B
1
0
1
B
1
0
2
A
0
1
3
B
0
0
I'm not familiar with teradata but in standard SQL next query should be working:
SELECT
T.*,
CASE WHEN Cnt = 2 THEN 1 ELSE 0 END AS BOTH_TYPES_PRESENT,
CASE WHEN Cnt = 1 AND Type = 'A' THEN 1 ELSE 0 END AS ONLY_A_PRESENT
FROM T
LEFT JOIN (
SELECT Id, COUNT(DISTINCT Type) Cnt FROM T WHERE Type IN ('A', 'B') GROUP BY Id
) CNT ON T.Id = CNT.Id;
SQL online editor

SQL -- Multiple rows, similar value in a row, need to not show specific values

Here is the issue:
Table name = a
1 2 3
123 1 A
123 1 A
123 2 A
332 1 A
332 1 A
321 2 B
321 2 A
321 1 A
So far what I have is this:
select distinct 1,2,3 from a where a.2='1' and a.3='B';
What it returns is each result (except for 321).
I only want to select values column 1 as long as that value is not in a row where there is a 2 in column 2 or a B in column 3. Is this possible?
"not in a row where there is a 2 in column 2 or a B in column 3" can be expressed as
select distinct 1,2,3 from a where a.2!='2' or a.3!='B';
or
select distinct 1,2,3 from a where a.2 <> '2' or a.3 <> 'B';
I would use group by and having:
select col1
from t
group by col1
having sum(case when col2 = 2 then 1 else 0 end) = 0 and
sum(case when col3 = 'B' then 1 else 0 end) = 0;

How do I count and replace elements in an sql column

I have a table with a column that contains numbers 1 - 5, it looks something like the following
Column
1
2
4
3
2
1
5
2
How do I count the number of times each number shows up so that my final table looks like this:
Number | Count
one | 2
two | 3
three | 1
four | 1
five | 1
Try this:
select
case
when number = 1 then 'one'
when number = 2 then 'two'
when number = 3 then 'three'
when number = 4 then 'four'
when number = 5 then 'five'
end number,
count
from
(select number,count(*) count
from yourtable
group by number) s
In this case you have only 5 values so case is feasible to do the replacement. However, good practice would be to use a table with the number to name mapping and then join it to your counting query. So, assuming you have table tblMap with 2 columns - number and name, you would do;
select name, count(*)
from
yourtable t
inner join tblMap m on t.number = m.number
group by t.number, name --group by number so that results are ordered by number
SELECT
CASE
WHEN columnx = 1 THEN 'one'
WHEN columnx = 2 THEN 'two'
WHEN columnx = 3 THEN 'three'
WHEN columnx = 4 THEN 'four'
WHEN columnx = 5 THEN 'five'
ELSE 'unexpected' END as Number
, COUNT(*) as count_of
FROM YourTable
GROUP BY
CASE
WHEN columnx = 1 THEN 'one'
WHEN columnx = 2 THEN 'two'
WHEN columnx = 3 THEN 'three'
WHEN columnx = 4 THEN 'four'
WHEN columnx = 5 THEN 'five'
ELSE 'unexpected' END
Which database you need this, if oracle then you can use below query provided your number are between the range of 1 and 5373484
-- works only for values between 1 and 5373484 (i.e julian date)
select to_char(to_date(num_column,'j'),'jsp'),cnt
from
( select num_column,count(1) cnt
From TableA
group by num_column
)
select
case
when [Column] = '1' then 'One'
when [Column] = '2' then 'Two'
when [Column] = '3' then 'Three'
when [Column] = '4' then 'Four'
when [Column] = '5' then 'Five'
end [Number]
, COUNT (*) as [Count] from Table_Name
group by [Column]

To retrieve records having only two specific values

Have the following Data in the table
Example Table
ID Value
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
I need to retrieve records having ID with only two values a and b.
So i am expecting only the Record with ID 3 .
Can anyone help me with the query
I guess you could do something like
select
ID,
sum(case when value = 'a' then 1
when value = 'b' then 1
else 3 end)
from
table1
group by id
having
sum (case when value = 'a' then 1
when value = 'b' then 1
else 3 end) =2
SQL Fiddle
That will work:
select x.id from
(
select id from mytable where value = 'a'
union all
select id from mytable where value = 'b'
) x
group by x.id
having COUNT(*) = 2
and not exists (select * from mytable t where t.id = x.id and value <> 'a' and value <> 'b')

Exclude value of a record in a group if another is present

In the example table below, I'm trying to figure out a way to sum amount over id for all marks where mark 'C' doesn't exist within an id. When mark 'C' does exist in an id, I want the sum of amounts over that id, excluding the amount against mark 'A'. As illustration, my desired output is at the bottom. I've considered using partitions and the EXISTS command, but I'm having trouble conceptualizing the solution. If any of you could take a look and point me in the right direction, it would be greatly appreciated :)
sample table:
id mark amount
------------------
1 A 1
2 A 3
2 B 2
3 A 2
4 A 1
4 B 3
5 A 1
5 C 3
6 A 2
6 C 2
desired output:
id sum(amount)
-----------------
1 1
2 5
3 2
4 4
5 3
6 2
select
id,
case
when count(case mark when 'C' then 1 else null end) = 0
then
sum(amount)
else
sum(case when mark <> 'A' then amount else 0 end)
end
from sampletable
group by id
Here is my effort:
select id, sum(amount) from table t where not t.id = 'A' group by id
having id in (select id from table t where mark = 'C')
union
select id, sum(amount) from table t where t.id group by id
having id not in (select id from table t where mark = 'C')
SELECT
id,
sum(amount) AS sum_amount
FROM atable t
WHERE mark <> 'A'
OR NOT EXISTS (
SELECT *
FROM atable
WHERE id = t.id
AND mark = 'C'
)
GROUP BY
id
;