I'm working with a custom DBMS (compliant with SQL 2011 Standard), and am trying to combine multiple columns into a single column like so, but am struggling with the syntax:
Current table:
------------------------------------------
| ID | setting_A | setting_B | setting_C |
------------------------------------------
| 1 | ON | OFF | UNKNOWN |
------------------------------------------
Desired query output:
------------------------------
| ID | Setting | Value |
------------------------------
| 1 | A | ON |
------------------------------
| 1 | B | OFF |
------------------------------
| 1 | C | UNKNOWN |
------------------------------
I've tried various IF and CASE statements, but have hit a wall. Any help would be appreciated.
You can unpivot with union all:
select id, 'A' setting, setting_A value from mytable
union all select id, 'B', setting_B from mytable
union all select id, 'C', setting_C from mytable
This assumes that setting_A, setting_B and setting_C are of the same datatype (otherwise, you need conversions to align the datatypes before combining the resultsets).
Demo on DB Fiddle:
id | setting | value
-: | :------ | :------
1 | A | ON
1 | B | OFF
1 | C | UNKNOWN
Related
I have a table where each row consists of an ID, date, variable values (eg. var1).
When there is a null value for var1 in a row, I want like to replace the null value with the most recent non-null value before that date for that ID. How can I do this quickly for a very large table?
So presume I start with this table:
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|Null |
| 2 |'01-02-2022'|Null |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|Null |
| 3 |'01-03-2022'|Null |
| 1 |'01-04-2022'|Null |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
Then I want this
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|55 |
| 2 |'01-02-2022'|12 |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|12 |
| 3 |'01-03-2022'|20 |
| 1 |'01-04-2022'|15 |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
cte suits perfect here
this snippets returns the rows with values, just an update query and thats all (will update my response).
WITH selectcte AS
(
SELECT * FROM testnulls where var1 is NOT NULL
)
SELECT t1A.id, t1A.date, ISNULL(t1A.var1,t1B.var1) varvalue
FROM selectcte t1A
OUTER APPLY (SELECT TOP 1 *
FROM selectcte
WHERE id = t1A.id AND date < t1A.date
AND var1 IS NOT NULL
ORDER BY id, date DESC) t1B
Here you can dig further about CTEs :
https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16
This question already has answers here:
MySQL - Split two columns into two different rows
(3 answers)
Closed 7 months ago.
I am still learning on SQL Statements
How do I append two columns?
E.g
Table 1
| ID | Name | Position |
------------------------------
| 1 | Mike | Developer
| 2 | Mark | QA |
Expected Result
Table 2
| ID | User Role/Name |
-----------------------
| 1 | Mike |
| 1 | Developer |
| 2 | Mark |
| 2 | QA |
-----------------------
Use union all:
select ID, Name as "User Role/Name" from table1
union all
select ID, position from table1
order by ID
DEMO
Do you means that it will output like it?
select ID, concat(Position,'/',Name) from Table2
| ID | User Role/Name |
-----------------------
| 1 | Developer/Mike |
| 2 | QA/Mark |
I have an Oracle table like this
| id | code | info | More cols |
|----|------|------------------|-----------|
| 1 | 13 | The Thirteen | dggf |
| 1 | 18 | The Eighteen | ghdgffg |
| 1 | 18 | The Eighteen | |
| 1 | 9 | The Nine | ghdfgjgf |
| 1 | 9 | Die Neun | ghdfgjgf |
| 1 | 75 | The Seventy-five | ghfgh |
| 1 | 75 | The Seventy-five | ghfgh |
| 1 | 2 | The Two | ghfgh |
| 1 | 27 | The Twenty-Seven | |
| 1 | 27 | The Twenty-Seven | |
| 1 | 27 | el veintisiete | fghfg |
| . | . | . | . |
| . | . | . | . |
| . | . | . | . |
In this table I want to find all rows with values in column code which have more than one distinct value in the info column. So from the listed rows this would be the values 9 and 27 and the associated rows.
I tried to construct a first query like
SELECT code FROM mytable
WHERE COUNT(DISTINCT info) >1
but I get a "ORA-00934: group function is not allowed here" error. Also I don't know how to express the condition COUNT(DISTINCT info) "with a fixed postcode".
You need having with group by - aggregate functions don't work with where clause
SELECT code
FROM mytable
group by code
having COUNT(DISTINCT info) >1
I would write your query as:
SELECT code
FROM yourTable
GROUP BY code
HAVING MIN(info) <> MAX(info);
Writing the HAVING logic this ways leaves the query sargable, meaning that an index on (code, info) should be usable.
You could also do this using exists logic:
SELECT DISTINCT code
FROM yourTable t1
WHERE EXISTS (SELECT 1 FROM yourTable WHERE t2.code = t1.code AND t2.info <> t1.info);
My first question on here, so i will try to explain it good.
I have a specific need which i tried to come up with a query but din't succeed to. Also googled it, and did not find it, but probably my input was not good, as it does not seem to me it should be that hard.
So some example of table and data i have (dates are in format here dd/MM/yyyy):
----------------------------------------------------------------------------
| id | asset_id | value | start_date | end_date |
----------------------------------------------------------------------------
| 1 | 1 | value1 | 20-10-2020 | 31-10-2020 |
----------------------------------------------------------------------------
| 1 | 1 | value1 | 01-11-2020 | 05-11-2020 |
----------------------------------------------------------------------------
| 1 | 2 | value2 | 05-10-2020 | 10-10-2020 |
----------------------------------------------------------------------------
| 1 | 2 | value3 | 10-10-2020 | 15-10-2020 |
----------------------------------------------------------------------------
| 1 | 3 | value3 | 15-08-2020 | 31-08-2020 |
----------------------------------------------------------------------------
| 1 | 3 | value1 | 01-09-2020 | 05-09-2020 |
----------------------------------------------------------------------------
| 1 | 3 | value1 | 05-09-2020 | 10-09-2020 |
----------------------------------------------------------------------------
So the specific need i have is to look at the two most recent rows grouped by id and asset_id. If the value of these two rows is the same, then combine the rows into one, with the start_date from the first row and end_date of the second one. If the values do not match, then nothing should be done.
For the specific input (previous table), some desired output should be:
----------------------------------------------------------------------------
| id | asset_id | value | start_date | end_date |
----------------------------------------------------------------------------
| 1 | 1 | value1 | 20-10-2020 | 05-11-2020 |
----------------------------------------------------------------------------
| 1 | 2 | value2 | 05-10-2020 | 10-10-2020 |
----------------------------------------------------------------------------
| 1 | 2 | value3 | 10-10-2020 | 15-10-2020 |
----------------------------------------------------------------------------
| 1 | 3 | value3 | 15-08-2020 | 31-08-2020 |
----------------------------------------------------------------------------
| 1 | 3 | value3 | 01-09-2020 | 10-09-2020 |
----------------------------------------------------------------------------
So for the group (id, asset_id) where the values are (1,1), two rows form the input table should be combined as i described as their value is the same. So the 1st and 2nd row should combine to the 1st row from the output. For the (1,2) group, the values are different, so no combining should be done. For the (1,3) group, the two most recent rows (the 6th and 7th from the input) should combine in the 5th in the output table.
It seems not hard, but i have trouble to come with something specific. I made an sqlfiddle where anyone can try.
Any help really appreciated.
You can filter the top two rows per group with row_number(). Then, aggregate by value: if both rows in the group have the same value, they are grouped together, else then end up in two different groups.
So:
select id, asset_id, value, min(start_date) start_date, max(end_date) end_date
from (
select t.*,
row_number() over(partition by id, asset_id order by start_date desc) rn
from mytable t
) t
where rn <= 2
group by id, asset_id, value
I have a table, and I'd like to select rows with the highest value. For example:
----------------
| user | index |
----------------
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | 4 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
----------------
Expected result:
----------------
| user | index |
----------------
| 1 | 1 |
| 2 | 2 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
----------------
How may I do so? I assume it can be done by some oracle function I am not aware of?
Thanks in advance :-)
You can use MAX() function for that with grouping user column like this:
SELECT "user"
,MAX("index") AS "index"
FROM Table1
GROUP BY "user"
ORDER BY "user";
Result:
| USER | INDEX |
----------------
| 1 | 1 |
| 2 | 2 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
See this SQLFiddle
if you have more than one column
select user , index
from (
select u.* , row_number() over (partition by user order by index desc) as rnk
from some_table u)
where rnk = 1
user is a reserved word - you should use a different name for the column.
select user,max(index) index from tbl
group by user;
Alternatively, you can use analytic functions:
select user,index, max(index) over (partition by user order by 1 ) highest from YOURTABLE
Note: Try NOT to use words like user, index, date etc.. as your column names, as they are reserved words for Oracle. If you will use, then use them with quotation marks, eg. "index", "date"...