Combining data from different rows into one - sql

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

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;

PSQL select either a or b in order but not both a and b if both a and b exists

I have a PSQL table
+--------+------+------+------+
| Col1 | Col2 | Col3 | Col4 |
+--------+------+------+------+
| 001 | 00A | 00B | 001 |
| 001001 | 00A | 00B | 001 |
| 002 | 00X | 00Y | 002 |
| 002002 | 00X | 00Y | 002 |
+--------+------+------+------+
I have the following PSQL query:
select *
from my_table
where (Col1 = '001' or Col4 = '001')
and Col2 = '00A'
order by Col3 asc;
I get the first two rows.
Here what happens is that it matches both conditions for OR condition. I need to match only one of the or conditions. That is if first condition (Col1='001001') is true then do not evaluate the next condition.
I need to select only the 2nd row (| 001001 | 00A | 00B | 001 |)
I have build another query using EXCEPT
select *
from my_table
where (Col1 = '001' or Col4 = '001')
and Col2 = '00A'
except (select *
from my_table
where Col1 != '001'
and Col2 = '00A')
order by Col3 asc
limit 1;
I would like to know if there is any other elegant queries for this job?
Your explanation is confusing as you say col1 = '001001' in one place and use 001 in the query. But I presume you want to use a hierarchy of comparison and return the one with the highest per each group ( col2,col3,col4) . Use DISTINCT ON. Change the condition in whichever way you like to return the appropriate row.
SELECT DISTINCT ON (col2, col3, col4) *
FROM my_table WHERE col2 = '00A'
ORDER BY col2,
col3,
col4,
CASE
WHEN col1 = '001001' THEN 1
WHEN col4 = '001' THEN 2
END;
DEMO
Does this give you what you want?
select *
from my_table
where (Col1 = '001' and Col2 != '00A')
or ((Col1 is null or Col1 = '') and Col4 = '001' and Col2 = '00A')
order by Col3 asc;

how to get distinct non-aggregated columns along with aggregated column when group by clause is applied in oracle?

select sum(col1), distinct col2 from table group by col1;
Above query fails. Is there an alternative to get distinct value if all the values in the group are unique?
For ex 1(if value in col2 is same):
|col1 | col2 |
|-----|------|
|1 | 2 |
|1 | 2 |
the output should be:
|col1(sum) |col2 |
|----------|-----|
| 2 | 2 |
ex 2(if value in col2 is different):
|col1 | col2 |
|-----|------|
|1 | 2 |
|1 | 3 |
the output should be:
|col1(sum) | col2 |
|----------|------|
| 2 |'...' |
DISTINCT is not an operation that is applied to a single column - it applies to all columns and does not make sense in the context of an aggregation.
the output should be:
col1(sum) col2
2 '...'
You can use a case statement to get your desired output but you will need to have all the outputs from the case statement having the same data-type; so, if you want ... when there are multiple values then you will need to convert your numbers to a string:
SELECT SUM( col1 ),
CASE
WHEN COUNT( DISTINCT col2 ) = 1
THEN TO_CHAR( MAX( col2 ) )
ELSE '...'
END
FROM your_table
GROUP BY col1
Do GROUP BY col1.
Have a case expression that returns col2 if there is only one distinct col2 value (for that col1 group.) Othwerwise return -999 (or any other value you chose).
select sum(col1),
case when count(distinct col2) = 1 then max(col2)
else -999
end
from t
group by col1

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

SQL Multiple rows into one row

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.