Converting column to rows in Oracle 11g - oracle11g

I have a table like this:
+----+----------+----------+----------+-----------+----------+----------+
| ID | AR_SCORE | ER_SCORE | FS_SCORE | CPF_SCORE | IF_SCORE | IS_SCORE |
+----+----------+----------+----------+-----------+----------+----------+
| 1 | 25 | 35 | 45 | 55 | 65 | 75 |
| 2 | 95 | 85 | 75 | 65 | 55 | 45 |
+----+----------+----------+----------+-----------+----------+----------+
And I need to extract this:
+----+----------+-------+
| ID | SCORE | VALUE |
+----+----------+-------+
| 1 | AR_SCORE | 25 |
| 1 | ER_SCORE | 35 |
| 2 | AR_SCORE | 95 |
+----+----------+-------+
I read many questions about how to use pivoting in oracle but I could not make it work.

The conversion from columns into rows is actually an UNPIVOT. Since you are using Oracle 11g there are a few ways that you can get the result.
The first way would be using a combination of SELECT yourcolumn FROM...UNION ALL:
select ID, 'AR_SCORE' as Score, AR_SCORE as value
from yourtable
union all
select ID, 'ER_SCORE' as Score, ER_SCORE as value
from yourtable
union all
select ID, 'FS_SCORE' as Score, FS_SCORE as value
from yourtable
union all
select ID, 'IF_SCORE' as Score, IF_SCORE as value
from yourtable
union all
select ID, 'IS_SCORE' as Score, IS_SCORE as value
from yourtable
order by id
See Demo. Using UNION ALL was how you needed to unpivot data prior to Oracle 11g, but starting in that version the UNPIVOT function was implemented. This will get you the same result with fewer lines of code:
select ID, Score, value
from yourtable
unpivot
(
value
for Score in (AR_SCORE, ER_SCORE, FS_SCORE, IF_SCORE, IS_SCORE)
) un
order by id
See Demo. Both will give a result:
| ID | SCORE | VALUE |
|----|----------|-------|
| 1 | AR_SCORE | 25 |
| 1 | FS_SCORE | 45 |
| 1 | IS_SCORE | 75 |
| 1 | IF_SCORE | 65 |
| 1 | ER_SCORE | 35 |
| 2 | FS_SCORE | 75 |
| 2 | IS_SCORE | 45 |
| 2 | ER_SCORE | 85 |
| 2 | IF_SCORE | 55 |
| 2 | AR_SCORE | 95 |

Related

In SQLite3, is it possible to list out specific rows?

Let's say I have a table:
+--------------+--------------+------+-----+
| ID | Score | email | add |
+--------------+--------------+------+-----+
| 123 | 88 | 123#gmail.com | somewhere |
| 456 | 77 | 123#gmail.com | somewhere |
| 789 | 88 | 123#gmail.com | somewhere |
| 111 | 77 |123#gmail.com | somewhere |
| 555 | 77 | 123#gmail.com | somewhere |
|444 | 88 | 123#gmail.com | somewhere
| 222 | 77 | 123#gmail.com | somewhere |
| 333 | 88 |123#gmail.com | somewhere |
My question is it possible to select Score column and ONLY print out first 3 88 and 77 Score?
I tried but it seems only give me 3 88 scores only
SELECT Score
FROM Table_Name
WHERE Score = '88' OR Score = '77'
LIMIT 3
First filter the table so that only the rows with the scores that you want are returned and then use ROW_NUMBER() window function to rank the rows of each Score based on ID so that you can filter out the rows that exceed the first 3 of each group:
SELECT ID, Score, email, add
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Score ORDER BY ID) rn
FROM Table_Name
WHERE Score = '88' OR Score = '77'
)
WHERE rn <= 3;
For versions of SQLite prior to 3.25.0 that do not support window functions use a correlated subquery:
SELECT t1.*
FROM Table_Name t1
WHERE t1.Score = '88' OR t1.Score = '77'
AND (SELECT COUNT(*) FROM Table_Name t2 WHERE t2.Score = t1.Score AND t2.ID <= t1.ID) <= 3;

R - Join two dataframes based on date difference

Let's consider two dataframes df1 and df2. I would like to join dataframes based on the date difference only. For Example;
Dataframe 1: (df1)
| version_id | date_invoiced | product_id |
-------------------------------------------
| 1 | 03-07-2020 | 201 |
| 1 | 02-07-2020 | 2013 |
| 3 | 02-07-2020 | 2011 |
| 6 | 01-07-2020 | 2018 |
| 7 | 01-07-2020 | 201 |
Dataframe 2: (df2)
| validfrom | pricelist| pricelist_id |
------------------------------------------
|02-07-2020 | 10 | 101 |
|01-07-2020 | 20 | 102 |
|29-06-2020 | 30 | 103 |
|28-07-2020 | 10 | 104 |
|25-07-2020 | 5 | 105 |
I need to map the pricelist_id and the pricelist based on the the validfrom column present in df2. Say that, based on the least difference between the date_invoiced (df1) and validfrom (df2), the row should be mapped.
Expected Outcome:
| version_id | date_invoiced | product_id | date_diff | pricelist_id | pricelist |
----------------------------------------------------------------------------------
| 1 | 03-07-2020 | 201 | 1 | 101 | 10 |
| 1 | 02-07-2020 | 2013 | 1 | 102 | 20 |
| 3 | 02-07-2020 | 2011 | 1 | 102 | 20 |
| 6 | 01-07-2020 | 2018 | 1 | 103 | 30 |
| 7 | 01-07-2020 | 201 | 1 | 103 | 30 |
I need to map purely based on the difference and the difference should be the least. Always, the date_invoiced (df1), should have closest difference comparing to validfrom (df2). Thanks
Perhaps you might want to try using date.table and nearest roll. Here, the join is made on DATE which would be DATEINVOICED from df1 and VALIDFROM in df2.
library(data.table)
setDT(df1)
setDT(df2)
df1$DATEINVOICED <- as.Date(df1$DATEINVOICED, format = "%d-%m-%y")
df2$VALIDFROM <- as.Date(df2$VALIDFROM, format = "%d-%m-%y")
setkey(df1, DATEINVOICED)[, DATE := DATEINVOICED]
setkey(df2, VALIDFROM)[, DATE := VALIDFROM]
df2[df1, on = "DATE", roll='nearest']

How to merge records based on consective fields in Teradata

I have a source like below table:
+---------+--+--------+--+---------+--+--+------+
| ID | | SEQ_NO | | UNIT_ID | | | D_ID |
+---------+--+--------+--+---------+--+--+------+
| 7979092 | | 1 | | 99 | | | 759 |
| 7979092 | | 2 | | -1 | | | 869 |
| 7979092 | | 3 | | -1 | | | 927 |
| 7979092 | | 4 | | -1 | | | 812 |
| 7979092 | | 5 | | 99 | | | 900 |
| 7979092 | | 6 | | 99 | | | 891 |
| 7979092 | | 7 | | -1 | | | 785 |
| 7979092 | | 8 | | -1 | | | 762 |
| 7979092 | | 9 | | -1 | | | 923 |
+---------+--+--------+--+---------+--+--+------+
I have to merge the rows when consecutive unit_id has same value. We should take max(D_id) when we consolidate the rows. Expected output is:
+---------+---------+------+
| ID | UNIT_ID | D_ID |
+---------+---------+------+
| 7979092 | 99 | 759 |
| 7979092 | -1 | 927 |
| 7979092 | 99 | 900 |
| 7979092 | -1 | 923 |
+---------+---------+------+
I have tried to find the solution using Teradata ordered analytical function, but did not find the solution. I use Teradata 16.
Thank You.
This logic is a bit quirky, it's based on two sequences created by different sort orders:
SELECT
ID
,UNIT_ID
,Max(D_ID)
FROM
(
SELECT
ID
,SEQ_NO
,UNIT_ID
,D_ID
-- assign the same value to consecutive UNIT_IDs
,SEQ_NO -
Row_Number()
Over(PARTITION BY ID, UNIT_ID
ORDER BY SEQ_NO) AS grp
FROM tab
) AS dt
GROUP BY 1,2,grp
You can use RESET WHEN to dynamically create groups within the window. Here's one way to do it:
select ID, UNIT_ID,
max(D_ID) over(
partition by ID order by SEQ_NO
reset when UNIT_ID <> UNIT_ID_prev -- Create new group for new value
) as D_ID
from (
select ID, SEQ_NO, UNIT_ID, D_ID,
lag(UNIT_ID) over(partition by ID order by SEQ_NO) as UNIT_ID_prev -- Previous value
from MY_TABLE
) src
qualify row_number() over(
partition by ID order by SEQ_NO
reset when UNIT_ID <> UNIT_ID_prev -- Match original max() window
) = 1 -- One row per group (similar to DISTINCT)

How to select sqlite columns based on a row lookup

I'm trying to compose an SQLite query and I've found a problem that's beyond my skillset. I'm trying to output columns that are based on the rows of another referenced table.
Food_List:
| food_id | name |
|---------|-----------|
| 1 | Apple |
| 2 | Orange |
| 3 | Pear |
Nutrient_Definition:
| nutrient_id | name |
|-------------|-----------|
| 21 | Carbs |
| 22 | Protein |
| 23 | Fat |
Nutrient_Data:
| food_id | nutrient_id | value |
|---------|-------------|-------|
| 1 | 21 | 50 |
| 1 | 22 | 24 |
| 1 | 23 | 63 |
| 2 | 22 | 12 |
| 2 | 23 | 95 |
| 3 | 21 | 66 |
| 3 | 22 | 87 |
| 3 | 23 | 38 |
Output:
| food_id | name | Carbs | Protein | Fat |
|---------|-----------|-------|---------|-----|
| 1 | Apple | 50 | 24 | 63 |
| 2 | Orange | | 12 | 95 |
| 3 | Pear | 66 | 87 | 38 |
(Note that Orange does not have a "Carbs" entry in the Nutrient_Data table)
I believe the following will do what you want :-
DROP TABLE IF EXISTS food_list;
CREATE TABLE IF NOT EXISTS food_list(food_id INTEGER PRIMARY KEY, name TEXT);
DROP TABLE IF EXISTS nutrient_definition;
CREATE TABLE IF NOT EXISTS nutrient_definition(nutrient_id INTEGER PRIMARY KEY, name TEXT);
DROP TABLE IF EXISTS nutrient_data;
CREATE TABLE IF NOT EXISTS nutrient_data(food_id INTEGER, nutrient_id INTEGER, value INTEGER);
INSERT INTO food_list (name) VALUES
('apple'),('orange'),('pear')
;
INSERT INTO nutrient_definition (name) VALUES
('carbs'),('protien'),('fat')
;
INSERT INTO nutrient_data VALUES
(1,1,50),(1,2,24),(1,3,63),
(2,2,12),(2,3,95),
(3,1,66),(3,2,87),(3,3,38)
;
SELECT food_list.food_id,food_list.name,
(
SELECT value
FROM nutrient_data
WHERE nutrient_data.food_id = food_list.food_id AND
nutrient_data.nutrient_id = (SELECT nutrient_definition.nutrient_id FROM nutrient_definition WHERE nutrient_definition.name = 'carbs')
),
(
SELECT value
FROM nutrient_data
WHERE nutrient_data.food_id = food_list.food_id AND
nutrient_data.nutrient_id = (SELECT nutrient_definition.nutrient_id FROM nutrient_definition WHERE nutrient_definition.name = 'protien')
),
(
SELECT value
FROM nutrient_data
WHERE nutrient_data.food_id = food_list.food_id AND
nutrient_data.nutrient_id = (SELECT nutrient_definition.nutrient_id FROM nutrient_definition WHERE nutrient_definition.name = 'fat')
)
FROM food_list
;
Results in :-

how to reference a result in a subquery

I have the following table in an sqlite database
+----+-------------+-------+
| ID | Week Number | Count |
+----+-------------+-------+
| 1 | 1 | 31 |
| 2 | 2 | 16 |
| 3 | 3 | 73 |
| 4 | 4 | 59 |
| 5 | 5 | 44 |
| 6 | 6 | 73 |
+----+-------------+-------+
I want to get the following table out. Where I get this weeks sales as one column and then the next column will be last weeks sales.
+-------------+-----------+-----------+
| Week Number | This_Week | Last_Week |
+-------------+-----------+-----------+
| 1 | 31 | null |
| 2 | 16 | 31 |
| 3 | 73 | 16 |
| 4 | 59 | 73 |
| 5 | 44 | 59 |
| 6 | 73 | 44 |
+-------------+-----------+-----------+
This is the select statement i was going to use:
select
id, week_number, count,
(select count from tempTable
where week_number = (week_number-1))
from
tempTable;
You are comparing values in two different rows. When you are just writing week_number, the database does not know which one you mean.
To refer to a column in a specific table, you have to prefix it with the table name: tempTable.week_number.
And if both tables have the same name, you have to rename at least one of them:
SELECT id,
week_number,
count AS This_Week,
(SELECT count
FROM tempTable AS T2
WHERE T2.week_number = tempTable.week_number - 1
) AS Last_Week
FROM tempTable;
In case of you want to take a query upon a same table twice, you have to put aliases on the original one and its replicated one to differentiate them
select a.week_number,a.count this_week,
(select b.count from tempTable b
where b.week_number=(a.week_number-1)) last_week
from tempTable a;

Resources