SQL Multiple rows into one row - sql

My Table data looks like
Col1 | Col2 | Col3
1 | NULL | NULL
NULL | 2 | NULL
NULL | NULL | 3
It is given that for any column there will be only entry. This means that, in the above data, if row1 has value for Col1, then there will be no row with value for Col1. Similarly, if row1 has value for Col1, it will not have value for any other column.
I want to write a query, so that I get only one row out for entire data (leaving NULL values). ie.
Col1 | Col2 | Col3
1 | 2 | 3

The easiest way to do this is using aggregation:
select max(col1) as col1, max(col2) as col2, max(col3) as col3
from t;

select
sum(ifnull(col1,0)) as col1,
sum(ifnull(col2,0)) as col2
sum(ifnull(col3,0)) as col3
from t;

Assuming the table is called tab the following query will work if there are only 3 columns:
select t1.Col1, t2.Col2, t3.Col3
from tab t1, tab t2, tab t3
where t1.Col1 is not null and t2.Col2 is not null and t3.Col3 is not null
The problem is the query will have to alias the table for each additional column. It may not be perfect, but it is a solution.

Related

Select query eliminating unwanted rows

I'm new to SQLite and I am having trouble finding the solution.
I have TABLE1 with columns col1 and col2
col1 col2
-------------
a no
a no
a yes
b no
c yes
c no
d yes
I want no repetitions from col1 but prioritize col2 when having "yes"
I want something like this
col1 col2
-------------
a yes
b no
c yes
d yes
You may try the following:
Approach 1
You may use row_number to retrieve a row number ordered by col2 in descending order that may be used to filter your results eg.
SELECT
col1,
col2
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY col1
ORDER BY col2 DESC
) rn
FROM
my_table
) t
WHERE rn=1;
col1
col2
a
yes
b
no
c
yes
d
yes
Approach 2
or simply use a group by col1 with the MAX function. The group by will ensure that for each col1 value you will receive the MAX of col2 that is yes if available and no if not.
SELECT
col1,
MAX(col2) as col2
FROM
my_table
GROUP BY
col1;
col1
col2
a
yes
b
no
c
yes
d
yes
View working demo on DB Fiddle
ggordon's answer will work well enough, but just since a window function isn't strictly necessary I figured I'd pass another solution:
select distinct
a.col1,
ifnull(b.col2, 'no') col2
from my_table a
left join (
select distinct
col1,
col2
from my_table
where col2 = 'yes'
) b on a.col1 = b.col1
Output:
| col1 | col2 |
| ---- | ---- |
| a | yes |
| b | no |
| c | yes |
| d | yes |
You will first want to do a distinct select on column one. Then you will want to make a case statement which is essentially a if statement in other languages. The case needs to be if column 1 is yes return it. if it is not yes then return no. It would look something like this
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
WHEN conditionN THEN resultN
ELSE result
END;

How to choose value in key table with multiple choice

I have a table A with the following type for data
col1 | col2
--------
e1 | A
e2 | A
e3 | B
e4 | B
.
.
Basically in the col1, the id points to 2 same values. I would like to get a table without the col2 duplication. So something like:
col1 | col2
--------
e1| A
e3| B
e5| C
.
.
Is there a way to achieve this in postgresql? I tried using the distinct keyword but they share the same id ...
You can use group by and min as follows:
Select min(col1) as col1,
Col2
From t
Group by col2;
You can use distinct on:
select distinct on (col2) t.*
from t
order by col2, col1 asc;
This selects all columns on the row.
If you want to delete rows, then you can use:
delete from t
where t.col1 < (select max(t2.col1) from t t2 where t2.col2 = t.col1);

Combining data from different rows into one

I have a database that looks something like this:
col1 | col2 | col3 | col4
User1 | Coms | Start | 19 June 2019
User1 | Coms | Ended | 20 June 2019
I would like to transpose the data into a single row, like this:
col1 | col2 | col3 | col4 | col5 (end status)
User1 | Coms | Start | 19 June 2019 | Ended
You see, this user Ended the session, meaning the second row of that transaction is pulled into the first row. If they did not end, the new End Status column will simply be a Null.
I know there is a function Stuff ... For XML Path query that can put some rows together into one comma delimited field, but this is not what I am looking for.
Any good ideas?
use conditional aggregation
select col1,col2,
max(case when col3='start' then col3 end),
max(case when col3='end' then col3 end),min(col4)
from table group by col1,col2
use conditional aggregation
select col1, col2,
max(case when col3='Start' then col3 end) as col3,
max(case when col3='Start' then col4 end) as col4,
max(case when col3='Ended' then 'Ended' end) as col5
from tablename
group by col1,col2

How to create column values by looking at other columns in a table? SQL

I have three columns in a table.
Requirements: The value of col2 and col3 should make col1.
Below shows the table I have right now, which needs to be change.
col1 col2 col3
AB football
AB football
ER driving
ER driving
TR city
TR city
Below shows the table that needs to be change to
col1 col2 col3
AB_football_1 AB football
AB_football_2 AB football
ER_driving_1 ER driving
ER_driving_2 ER driving
TR_city_1 TR city
TR_city_2 TR city
As you can see in col1, it should take col2, put (underscore), then col3, put (underscore) then increment the number according to the values in col2 and col3.
Can this be approached within CREATE or SELECT or INSERT statement or Trigger Statement, if so any tips would be grateful.
Try as
SELECT col2
||'_'
||col3
||'_'
||rank col1,
col2,
col3
FROM (SELECT col2,
col3,
ROW_NUMBER()
OVER(
PARTITION BY col2, col3
ORDER BY col2) rank
FROM my_table)
Output
+---------------+------+----------+
| COL1 | COL2 | COL3 |
+---------------+------+----------+
| AB_football_1 | AB | football |
| AB_football_2 | AB | football |
| ER_driving _1 | ER | driving |
| ER_driving _2 | ER | driving |
| TR_city _1 | TR | city |
| TR_city _2 | TR | city |
+---------------+------+----------+
/* table is */
col1 col2 col3
test 123
/* Try this query */
UPDATE `demo`
SET `col1` = concat(col2, '_', col3)
/* Output will be */
col1 col2 col3
test_123 test 123
This is easy to do (at SELECT) using row_number() window function , something like this:
select
col2 ||'_'|| col3 ||'_'|| row_number() over(partition by col2, col3 order by col2) as col1,
col2,
col3
from t

select distinct col1 with min(col2) and max(col3) from table

My table looks like this with duplicates in col1
col1, col2, col3, col4
1, 1, 0, a
1, 2, 1, a
1, 3, 1, a
2, 4, 1, b
3, 5, 0, c
I want to select distinct col1 with max (col3) and min(col2);
so result set will be:
col1, col2, col3, col4
1, 2, 1, a
2, 4, 1, b
3, 5, 0, c
I have a solution but looking for best ideas?
SELECT col1, MAX(col3) AS col3, MIN(col2) AS col2, MAX(col4) AS col4
FROM MyTable
GROUP BY col1;
You showed in your example that you wanted a col4 included, but you didn't say which value you want. You have to put that column either in an aggregate function or in the GROUP BY clause. I assumed that taking the max for the group would be acceptable.
update: Thanks for the clarification. You're asking about a variation of the greatest-n-per-group problem that comes up frequently on Stack Overflow. Here's my usual solution:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t3
ON t1.col1 = t3.col1 AND t1.col3 < t3.col3
WHERE t3.col1 IS NULL;
In English: show me the row (t1) for which no row exists with the same col1 and a greater value in col3. Some people write this using a NOT EXISTS subquery predicate, but I prefer the JOIN syntax.
Here's the output from my test given your example data:
+------+------+------+------+
| col1 | col2 | col3 | col4 |
+------+------+------+------+
| 1 | 2 | 1 | a |
| 1 | 3 | 1 | a |
| 2 | 4 | 1 | b |
| 3 | 5 | 0 | c |
+------+------+------+------+
Notice that there are two rows for col1 value 1, because both rows satisfy the join condition; no other row exists with a greater value in col3.
So we need to add another condition to resolve the tie. You want to compare to rows with a lesser value in col2 and if no such rows exist, then we've found the row with the least value in col2.
SELECT t1.*
FROM MyTable t1
LEFT OUTER JOIN MyTable t3
ON t1.col1 = t3.col1 AND t1.col3 < t3.col3
LEFT OUTER JOIN MyTable t2
ON t1.col1 = t2.col1 AND t1.col3 = t2.col3 AND t1.col2 > t2.col2
WHERE t2.col1 IS NULL AND t3.col1 IS NULL;
Here's the output from my test given your example data:
+------+------+------+------+
| col1 | col2 | col3 | col4 |
+------+------+------+------+
| 1 | 2 | 1 | a |
| 2 | 4 | 1 | b |
| 3 | 5 | 0 | c |
+------+------+------+------+
PS: By the way, it's customary on Stack Overflow to edit your original question and add detail, instead of adding answers to your own question that only clarify the question. But I know some actions aren't available to you until you have more than 1 reputation point.