I have the following table data:
teams
tournament
assoc
player_id
MT
101
EGY
100696
MT
101
EGY
100439
MT
101
EGY
102486
MT
101
EGY
111887
MT
101
NGR
113563
MT
101
NGR
111959
MT
101
NGR
145024
MT
101
NGR
104514
MT
101
NGR
112092
WT
101
EGY
202375
WT
101
EGY
116724
WT
101
EGY
134971
WT
101
EGY
200157
WT
101
NGR
102441
WT
101
NGR
146169
WT
101
NGR
134970
WT
101
NGR
133736
WT
101
NGR
101247
I would like to transpose rows to columns and get the following:
teams
tournament
assoc
player_id1
player_id2
player_id3
player_id4
player_id5
MT
101
EGY
100696
100439
102486
111887
MT
101
NGR
113563
111959
145024
104514
112092
WT
101
EGY
202375
116724
134971
200157
WT
101
NGR
102441
146169
134970
133736
101247
Needs to group by assoc, tournament and teams and max columns of player_idx can be 5.
Tried solutions for Pivot tables with no success.
with cte as (select teams, tournament, assoc, player_id, row_number() over (partition by teams, tournament, assoc) as rownum from mytable)
select teams, tournament, assoc,
max(case rownum when 1 then player_id end) as player_id1,
max(case rownum when 2 then player_id end) as player_id2,
max(case rownum when 3 then player_id end) as player_id3,
max(case rownum when 4 then player_id end) as player_id4,
max(case rownum when 5 then player_id end) as player_id5
from cte
group by teams, tournament, assoc;
+-------+------------+-------+------------+------------+------------+------------+------------+
| teams | tournament | assoc | player_id1 | player_id2 | player_id3 | player_id4 | player_id5 |
+-------+------------+-------+------------+------------+------------+------------+------------+
| MT | 101 | EGY | 100439 | 100696 | 102486 | 111887 | NULL |
| MT | 101 | NGR | 104514 | 111959 | 112092 | 113563 | 145024 |
| WT | 101 | EGY | 116724 | 134971 | 200157 | 202375 | NULL |
| WT | 101 | NGR | 101247 | 102441 | 133736 | 134970 | 146169 |
+-------+------------+-------+------------+------------+------------+------------+------------+
Tested on MySQL 8.0, and on this dbfiddle on MariaDB 10.3:
https://dbfiddle.uk/?rdbms=mariadb_10.3&fiddle=ec2fc62b17fdc5eac9198f9298f229cc
Related
Let's say I have two tables as following:
+--------------+-------+
| ID | Score |
+--------------+-------
| 123 | 88 |
| 456 | 77 |
| 789 | 88 |
| 111 | 77 |
| 555 | 77 |
|444 | 88 |
| 222 | 77 |
| 333 | 88 |
SECOND TABLE:
+--------------+-----+
| ID |NAME | FScore |
+--------------+-------
| 123 |John | 106 |
| 456 |Aaron | 99 |
| 789 |Dan | 105 |
| 111 |Kevin | 200 |
| 555 |Tom | 100 |
| 444 |Jeff | 120 |
| 222 |Carl | 65 |
| 333 |Wayne | 101 |
I want to join two tables and based on FScore find out top 3 88 and top 3 77 rows like:
+--------------+--------------+------+-----+
| ID | Score | NAME | FScore |
+--------------+--------------+------+-----+
| 444 | 88 | Jeff | 120 |
| 123 | 88 | John | 106 |
| 789 | 88 | Dan | 105 |
Any helps are appreciated!
You can use a CTE that returns the joined tables and then filter the resultset with a correlated subquery:
WITH cte AS (
SELECT *
FROM table1 t1 INNER JOIN table2 t2
ON t2.ID = t1.ID
WHERE t1.Score IN ('77', '88')
)
SELECT c1.ID, c1.Score, c1.Name, c1.FScore
FROM cte c1
WHERE (SELECT COUNT(*) FROM cte c2 WHERE c2.Score = c1.Score AND c2.FScore >= c1.FScore) <= 3;
Or, with ROW_NUMBER() window function:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY t1.Score ORDER BY t2.FScore DESC) rn
FROM table1 t1 INNER JOIN table2 t2
ON t2.ID = t1.ID
WHERE t1.Score IN ('77', '88')
)
SELECT ID, Score, Name, FScore
FROM cte
WHERE rn <= 3;
See the demo.
I have three data tables and they are given below. My first table name is product_table, the second table name is product_purchase_table, and the third table name is product_transfer_table. I'm trying to join these three tables like table name Table After Joint which is given below. My data will be joint once after another following the date like the given Table(Table After Joint).
product_table
row_id product_id product_name
1 101 Accounting Book
Product_Purchase_table
row_id product_id date quantity price
1 101 2020-10-25 100 1000
2 101 2020-10-29 200 2000
Product_transfer_table
row_id product_id date t_quantity t_price
1 101 2020-10-26 10 120
2 101 2020-10-27 15 180
3 101 2020-10-30 5 60
Table After Joint
row_id product_id product_name date quantity price t_quantity t_price
1 101 Accounting Book 2020-10-25 100 1000
2 101 Accounting Book 2020-10-26 10 120
3 101 Accounting Book 2020-10-27 15 180
4 101 Accounting Book 2020-10-29 200 2000
5 101 Accounting Book 2020-10-30 5 60
You need a FULL OUTER join of Product_Purchase_table and Product_transfer_table (emulated by LEFT joins and UNION ALL because SQLite does not support FULL OUTER join) and INNER join the result to product_table
SELECT row_number() over (partition by pt.product_id order by t.date) row_id,
pt.product_id, pt.product_name,
t.date, t.quantity, t.price, t.t_quantity, t.t_price
FROM product_table pt
INNER JOIN (
SELECT ppt.product_id, ppt.date, ppt.quantity, ppt.price,
ptt.t_quantity, ptt.t_price
FROM Product_Purchase_table ppt LEFT JOIN Product_transfer_table ptt
ON ptt.product_id = ppt.product_id AND ptt.date = ppt.date
UNION ALL
SELECT ptt.product_id, ptt.date, ppt.quantity, ppt.price,
ptt.t_quantity, ptt.t_price
FROM Product_transfer_table ptt LEFT JOIN Product_Purchase_table ppt
ON ptt.product_id = ppt.product_id AND ptt.date = ppt.date
WHERE ppt.product_id IS NULL
) t ON t.product_id = pt.product_id
ORDER BY pt.product_id, t.date
See the demo.
Results:
> row_id | product_id | product_name | date | quantity | price | t_quantity | t_price
> -----: | ---------: | :-------------- | :--------- | -------: | ----: | :--------- | :------
> 1 | 101 | Accounting Book | 2020-10-25 | 100 | 1000 | null | null
> 2 | 101 | Accounting Book | 2020-10-26 | null | null | 10 | 120
> 3 | 101 | Accounting Book | 2020-10-27 | null | null | 15 | 180
> 4 | 101 | Accounting Book | 2020-10-29 | 200 | 2000 | null | null
> 5 | 101 | Accounting Book | 2020-10-30 | null | null | 5 | 60
I tried reading an Excel file where I need to read sub columns too, but not getting a way to resolve this.
The Excel file contains data as,
| Sl No. | Sales 1 | Sales 2 | % Change |
| | 1 Qtr | % Qtr | 2 Qtr| % Qtr | |
| 1 | 134 | 67 | 175 | 74 | 12.5 |
After importing I can see the data as
| Sl No. |Sales 1| ...3 |Sales 2 | ...5 | % Change |
| NA | 1 Qtr | % Qtr | 2 Qtr | % Qtr | NA |
| 1 | 134 | 67 | 175 | 74 | 12.5 |
I tried several ways to merge "Sales 1 & ...3 and Sales 2 & ...5" and keep 1 Qtr,% Qtr,2 Qtr,% Qtr as sub columns, but unable to do so
I need it to be like,
| Sl No. | Sales 1 | Sales 2 | % Change |
| | 1 Qtr | % Qtr | 2 Qtr| % Qtr | |
| 1 | 134 | 67 | 175 | 74 | 12.5 |
Unfortunately, R doesn't allow for multiple colnames. So probably the easiest thing you can do using base R is combining the colnames and then getting rid of the first line.
library(openxlsx)
x <- read.xlsx("your_file.xlsx")
# Sl.No Sales.1 X3 Sales.2 X5 %Change
# 1 NA 1 Qtr %Qtr 2 Qtr %Qtr NA
# 2 1 134 67 175 74 12.5
colnames(x) <- paste0(colnames(x),ifelse(is.na(x[1,]),"",paste0(" - ", x[1,])))
x <- x[-1,]
# Sl.No Sales.1 - 1 Qtr X3 - %Qtr Sales.2 - 2 Qtr X5 - %Qtr %Change
# 2 1 134 67 175 74 12.5
colnames(x)
# [1] "Sl.No" "Sales.1 - 1 Qtr" "X3 - %Qtr" "Sales.2 - 2 Qtr" "X5 - %Qtr" "%Change"
I'm having a problem with my SQLite pivot code, mainly taken from McPeppr's answer here: Pivot in SQLite
Creating my temp table:
WITH t1 AS (
SELECT band,
p.name,
status,
strftime('%Y-%m', time_start) AS Month,
AVG(time) AS Avg
FROM person p
JOIN action a ON p.person_id = a.person_id
JOIN log l ON p.log_id = l.log_id
WHERE p.person = 'Joe' AND opps = '2'
GROUP BY band, Month, status, strftime('%Y-%m', time_stamp_start)
ORDER BY Month, CASE status
WHEN 'one' THEN 0
WHEN 'two' THEN 1
WHEN 'three' THEN 2
WHEN 'four' THEN 3
END
),
t1 looks like:
band | name | status | month | AVG
------+--------+--------+-----------+---------------
1 | Joe | one | 2018-01 | 3.33
2 | Joe | one | 2018-01 | 4.11
1 | Joe | two | 2018-02 | 2.55
2 | Joe | two | 2018-02 | 3.45
..........
When I try pivot in a select I get:
Select band, Month,
case when status = 'one' then response_avg end as One,
case when status = 'two' then response_avg end as Two,
...,
from t1
This:
band | month | One | Two
------+------------+-------+---------
1 | 2018-01 | 3.41 | NULL
2 | 2018-01 | 3.55 | NULL
1 | 2018-01 | NULL | 2.55
2 | 2018-01 | NULL | 4.61
1 | 2018-02 | 1.55 | NULL
2 | 2018-02 | 2.43 | NULL
1 | 2018-02 | NULL | 4.33
2 | 2018-02 | NULL | 3.44
Whereas I want
band | month | One | Two
------+------------+-------+---------
1 | 2018-01 | 3.41 | 2.55
2 | 2018-01 | 3.55 | 4.61
1 | 2018-02 | 1.55 | 2.55
2 | 2018-02 | 2.43 | 4.61
I understand that the status column is causing this but can't figure out how to fix it.
I've tried a good few methods (multiple temp tables, sub-selects to remove the "status" due to default grouping) from different questions I found on here but keep ending up with the same result. Any help appreciated
The trick when you are using CASE/WHEN is to use aggregative functions like MAX and then group by all the non-aggragate columns :
SELECT
band,
Month,
MAX(CASE
when status = 'one' then response_avg
END) as One,
MAX(CASE
when status = 'two' then response_avg
END) as Two
FROM t1
GROUP BY band,
Month
My question is:
i have two tables(A and B) as below
A
deal_no deal_date deal_amnt
501 `20180525` `10`
502 `20180526` `20`
601 `20180528` `30`
602 `20180529` `40`
B
deal_type maturity_date
501 `20180525`
502 `20180527`
601 `20180530`
602 `20180530`
For the same deal_no(deal_type),if deal_date from A = maturity_date from B then deal_amnt for maturity_date should be same
eg(for 501--> if(20180525=20180525) then amnt=10)
For the same deal_no(deal_type),if deal_date from A < maturity_date from B then deal_amnt for maturity_date should be same,and it same amount should be upadted under deal_date
eg(for 502--> if(20180526 < 20180527) then amount for 20180527=20 and for 20180526 should also =20)
however, if i am having more than one deal_date having same maturity_date then amount for maturity_date should be sum of that two or more deal_dates.
eg(for 601 --> if(20180528 < 20180530) and for 602 --> if(20180529 < 20180530)
then amount for 20180528=30 and amount for 20180529 should =((previous 30)+(current 40))=70 and amount for 20180530 should be 70 as outstanding)
I have fortnightly(fourteen)dates,i want op as 14 dates and amount based on deal date and maturity date
op should be:
date `deal_amnt`
20180516 0
20180517 0
20180518 0
20180519 0
20180520 0
20180521 0
20180522 0
20180523 0
20180524 0
20180525 10
20180526 20
20180527 20
20180528 30
20180529 70
20180530 70
Need help i am using plsql
Here's one solution purely SQL no PL needed
SQL Fiddle
Query 1:
with dts(n, dt) as (
select 1 n
, date '2018-05-16'
from dual
union all
select n+1
, date '2018-05-16' + n
from dts where n < 15
)
select dt
, sum(deal_amnt)
from a
join b
on a.deal_no = b.deal_type
right join dts
on dts.dt between a.deal_date and b.maturity_date
group by dt
Results:
| DT | SUM(DEAL_AMNT) |
|----------------------|----------------|
| 2018-05-16T00:00:00Z | (null) |
| 2018-05-17T00:00:00Z | (null) |
| 2018-05-18T00:00:00Z | (null) |
| 2018-05-19T00:00:00Z | (null) |
| 2018-05-20T00:00:00Z | (null) |
| 2018-05-21T00:00:00Z | (null) |
| 2018-05-22T00:00:00Z | (null) |
| 2018-05-23T00:00:00Z | (null) |
| 2018-05-24T00:00:00Z | (null) |
| 2018-05-25T00:00:00Z | 10 |
| 2018-05-26T00:00:00Z | 20 |
| 2018-05-27T00:00:00Z | 20 |
| 2018-05-28T00:00:00Z | 30 |
| 2018-05-29T00:00:00Z | 70 |
| 2018-05-30T00:00:00Z | 70 |