How to join two tables but not to repeat rows in mysql - mysql

I am facing one issue for getting data. I am new in Mysql. Firstly i will show my table structure
order_products
id user_id product_id product_name
1 1 10 Jacket1
2 1 10 Jacket2
order_products_sizes
id order_product_id size qty
1 1 S 56
2 1 M 36
3 1 XL 36
4 1 2XL 56
5 2 S 32
6 2 M 28
7 2 XL 28
8 2 2XL 32
9 2 3XL 69
My expected Output:-
product_name S M XL 2XL 3XL
JACKET1 56 36 36 56
JACKET2 32 28 28 32 69
for first row 3xl would be empty beacuse there is no size available in order_product_sizes
Actually i am using join but when i use join the rows are repeating because of joining two table that is actual behavior of joins.
I have tries so far:-
SELECT order_products.product_name,
CASE
WHEN order_product_sizes.order_product_id = order_products.id AND
order_product_sizes.size = 'L' THEN order_product_sizes.qty
END AS L
from order_products
join
order_product_sizes
on order_products_sizes.order_product_id = order_products.id;

You can try below - using conditional aggregation
SELECT order_products.product_name,
max(CASE
WHEN
order_product_sizes.size = 'S' THEN order_product_sizes.qty
END) AS S,
max(CASE
WHEN
order_product_sizes.size = 'M' THEN order_product_sizes.qty
END) AS M,
max(CASE
WHEN
order_product_sizes.size = 'XL' THEN order_product_sizes.qty
END) AS XL,
max(CASE
WHEN
order_product_sizes.size = '2XL' THEN order_product_sizes.qty
END) AS '2XL',
max(CASE
WHEN
order_product_sizes.size = '3XL' THEN order_product_sizes.qty
END) AS '3XL'
from order_products join order_products_sizes
on order_products_sizes.order_product_id = order_products.id
group by order_products_sizes.order_product_id

Related

How to Combine multiple rows to single row based on a column in MySQL or Hive

I need to generate average sales per Title between year 2019 to 2021. There are 2 input tables:
Title Table
Title_id Title_type Price_per
1 tv 10
2 book 50
3 cd 20
Transactions table(trans)
tran_id Title_id Qty year
1 3 2 2019
2 1 1 2019
3 3 5 2020
4 3 3 2020
5 1 10 2021
The expected result should generate below columns:
Title_id|Avg_sales_2019|Avg_sales_2020|Avg_sales_2021
title_id avg_sales_2019 avg_sales_2020 avg_sales_2021
1 10.0 NULL 100.0
3 40.0 80.0 NULL
I used below query, but it does not generate the expected output
select a.title_id,
case when a.year=2019 then avg end as Avg_sales_2019,
case when a.year=2020 then avg end as Avg_sales_2020,
case when a.year=2021 then avg end as Avg_sales_2021
from (Select t.title_id, x.year, AVG(t.Price_per*x.Qty) as avg
from title t join trans x on t.title_id=x.title_id
group by t.title_id,x.year) a;
title_id avg_sales_2019 avg_sales_2020 avg_sales_2021
1 10.0 NULL NULL
1 NULL NULL 100.0
3 40.0 NULL NULL
3 NULL 80.0 NULL
How to combine the rows for a particular title_id to get the expected result
Note: I am running the query in Hive
Use conditional aggregation:
SELECT
t.title_id,
AVG(CASE WHEN x.year = 2019
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2019,
AVG(CASE WHEN x.year = 2020
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2020,
AVG(CASE WHEN x.year = 2021
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2021
FROM title t
LEFT JOIN trans x
ON x.title_id = t.title_id
GROUP BY
t.title_id
ORDER BY
t.title_id;

MYSQL query to display max values of column grouped by inner join column

I have two tables
PILOTS
pilot_id
first_name
last_name
status
hub
1
fname1
lname1
1
YBBN
2
fname2
lname2
0
YSSY
3
fname3
lname3
1
YMML
4
fname4
lname4
1
YBBN
5
fname5
lname5
1
EGLL
6
fname6
lname6
1
EGLL
7
fname7
lname7
1
EGLL
8
fname8
lname8
1
YPAD
PIREPS
pirep_id
pilot_id
date
landing_rate
accepted
1
1
2021-04-01
-113
1
2
1
2021-04-02
-110
1
3
1
2021-04-03
-200
1
4
2
2021-04-04
-20
1
5
2
2021-04-05
-120
1
6
3
2021-04-06
-130
1
7
3
2021-04-07
-132
1
8
4
2021-04-08
-91
1
9
5
2021-04-09
-64
1
10
6
2021-04-10
-47
0
11
6
2021-04-11
-112
1
12
7
2021-04-12
-113
1
13
7
2021-04-13
-201
1
14
1
2021-04-14
-300
0
15
1
2021-04-15
-301
1
EXPECTED REUSULT
pilot_id
first_name
last_name
hub
landing_rate
date
pirep_id
2
fname2
lname2
YSSY
-20
2021-04-04
4
5
fname5
lname5
EGLL
-64
2021-04-09
9
4
fname4
lname4
YBBN
-91
2021-04-08
8
3
fname3
lname3
YMML
-130
2021-04-06
6
8
fname8
lname8
YPAD
-301
2021-04-15
15
The below code gives me the expected output if I only group by pilot ID and displays the best landing rate with the associated pilot and the date they completed the flight
SELECT pi.first_name,pi.last_name,p.pirep_id,p.pilot_id,p.date,p.landing_rate
FROM qvi_pireps p
LEFT JOIN qvi_pilots pi on p.pilot_id=pi.pilot_id
INNER JOIN
(SELECT pilot_id as pil,date as da,MAX(landing_rate) AS max_landing_rate
FROM qvi_pireps
where landing_rate<0 GROUP BY pilot_id) grouppedp
ON p.pilot_id = grouppedp.pil
AND p.landing_rate = grouppedp.max_landing_rate
where pi.status=1 and
accepted=1
group by p.pilot_id ORDER BY `grouppedp`.`max_landing_rate` DESC,p.date asc limit 20
ABOVE QUERY OUTPUT
first_name
last_name
pirep_id
pilot_id
date
landing_rate
fname2
lname2
4
2
2021-04-04
-20
fname5
lname5
9
5
2021-04-09
-64
fname4
lname4
8
4
2021-04-08
-91
fname1
lname1
2
1
2021-04-02
-110
fname6
lname6
11
6
2021-04-11
-112
fname7
lname7
12
7
2021-04-12
-113
fname3
lname3
6
3
2021-04-06
-130
fname8
lname8
15
8
2021-04-15
-301
when I change group by p.pilot_id to group by pi.hub I receive the unique hubs however the pilot,landing_rate and date do not match what should be the best
Basically, what I'm trying to achieve is getting the MAX(landing_rate) of each pilot where pilot.status=1 & flight.accepted=1 then group by pilot.hub to display the best hub with the highest landing rate with the pilot and date they achieved that landing rate
Any help would be greatly appreciated!
This:
SELECT pilot_id, date, MAX(landing_rate)
FROM qvi_pireps
GROUP BY pilot_id
is invalid SQL. You group by pilot and select a date. Which date? There are many dates per pilot in that table. You'd have to apply some aggregation function on date to get this valid. MySQL should raise an exception here (and I am sure it would, did you change from cheating mode to SET sql_mode = 'ONLY_FULL_GROUP_BY';. This should be set by default and as this doesn't seem to be the case, I surmise you are working with a old version of MySQL.
Apart from this and the inappropriate outer join and the missing accepted check in your subquery (which may be the main reason you are seeing incorrect dates), your query looks rather fine. Only that in your main query you group again by pilot, which makes no sense at all. Maybe you left that in by mistake when rewriting your query at some point. Here is your query corrected:
SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id AND pir.accepted = 1
JOIN
(
SELECT pilot_id, MAX(landing_rate) AS max_landing_rate
FROM qvi_pireps
WHERE accepted = 1
GROUP BY pilot_id
) grouppedp ON grouppedp.pilot_id = pir.pilot_id AND grouppedp.max_landing_rate = pir.landing_rate
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;
For readability, though I prefer an IN clause over a join:
SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id
AND pir.accepted = 1
AND (pir.pilot_id, pir.landing_rate) IN
(
SELECT pilot_id, MAX(landing_rate)
FROM qvi_pireps
WHERE accepted = 1
GROUP BY pilot_id
)
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;
(The same can be achieved with NOT EXISTS (<a greater landing rate for the pilot>) by the way.)
In current MySQL versions we would rather use a window function in order to access the qvi_pireps table only once:
SELECT first_name, last_name, pirep_id, pilot_id, date, landing_rate
FROM
(
SELECT
pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate,
MAX(pir.landing_rate) OVER (PARTITION BY pil.pilot_id) AS max_landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id AND pir.accepted = 1
WHERE pil.status = 1
) with_max_landing_rate
WHERE landing_rate = max_landing_rate
ORDER BY landing_rate DESC, date ASC
LIMIT 20;
UPDATE: Same query for old MySQL versions, but for best rate per hub instead of best rate per pilot.
After all, this simply means we must look for the MAX(landing_rate) per hub instead of per pilot:
SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id
AND pir.accepted = 1
AND (pil.hub, pir.landing_rate) IN
(
SELECT pl.hub, MAX(pr.landing_rate)
FROM qvi_pireps pr
JOIN qvi_pilots pl USING (pilot_id)
WHERE pr.accepted = 1 AND pl.status = 1
GROUP BY pl.hub
)
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;

bifurcating the values basis bucket and count using MySQL

I have below mentioned three tables.
Table1:
ID Ref_ID category_id Date
II-1 xrt-11-gt 1 2019-01-01 15:34:18
II-2 xtt-10-xt 1 2019-01-05 17:14:20
II-3 xyt-09-yu 2 2019-02-04 11:04:12
II-4 xet-12-ct 2 2019-02-01 12:33:14
Table2
Ref_ID2 Value
xrt-11-gt 150
xrt-11-gt 175
xrt-11-gt 165
xrt-11-gt 168
xtt-10-xt 200
xtt-10-xt 45
xyt-09-yu 34
xet-12-ct 78
Table3
ref type
1 Active
2 InActive
3 Hold
I have a query, like
select a.ID,a.Date,b.Value,c.type from Table1 a
left join Table2 b on a.Ref_ID=b.Ref_ID2
left join Table3 c on a.category_id=c.ref;
which return me below mentioned output.
ID Value Type Date
II-1 150 Active 2019-01-01 15:34:18
II-1 175 Active 2019-01-01 15:34:18
II-1 165 Active 2019-01-01 15:34:18
II-1 168 Active 2019-01-01 15:34:18
II-2 200 InActive 2019-01-05 17:14:20
II-2 45 InActive 2019-01-05 17:14:20
II-3 34 InActive 2019-02-04 11:04:12
II-4 78 InActive 2019-02-01 12:33:14
I need to convert the above output in the below mentioned format in MySQL itself.
Where, the 1-3 and 3-5 are the bifurcation of count of ID basis on the bucket it fall as per the Type.
Month Total Active 1-3 3-5 InActive 1-3 3-5 Hold 1-3 3-5
Jan-19 6 2 1 1 0 0 0 0 0 0
Feb-19 2 0 0 0 2 2 0 0 0 0
Is this what you are looking for:
SELECT
DATE_FORMAT(date, '%b-%y') month,
COUNT(*) total,
SUM(type = 'Active') active,
CASE WHEN SUM(type = 'Active') BETWEEN 1 AND 3 THEN SUM(type = 'Active') ELSE 0 END `1-3`,
CASE WHEN SUM(type = 'Active') BETWEEN 4 AND 5 THEN SUM(type = 'Active') ELSE 0 END `4-5`,
SUM(type = 'InActive') inactive,
CASE WHEN SUM(type = 'InActive') BETWEEN 1 AND 3 THEN SUM(type = 'InActive') ELSE 0 END `1-3`,
CASE WHEN SUM(type = 'InActive') BETWEEN 4 AND 5 THEN SUM(type = 'InActive') ELSE 0 END `4-5`,
SUM(type = 'Hold') hold,
CASE WHEN SUM(type = 'Hold') BETWEEN 1 AND 3 THEN SUM(type = 'Hold') ELSE 0 END `1-3`,
CASE WHEN SUM(type = 'Hold') BETWEEN 4 AND 5 THEN SUM(type = 'Hold') ELSE 0 END `4-5`
FROM
Table1 a
LEFT JOIN Table2 b on a.Ref_ID=b.Ref_ID2
LEFT JOIN Table3 c on a.category_id=c.ref
GROUP BY DATE_FORMAT(date, '%b-%y');
Note that this will not return exactly what you are showing in your expected output. Especially, there will be a few differences in the first record, that is showing aggregated data for January: total will be 6 for that month, with 4 active. But this is what I understood from your requirement.

How to use SUM with INNER JOIN from two different tables

I am stuck on a query where i have to show list of manufacturers and the Amount of Loan they took and Amount of Refund they returned. i have generated the query but i want to sum total no: of refunds of a manufacturer and total no: of Loans manufacturer has taken. and the difference , that is LoanTaken - RefundAmount = Remaining Amount. If its possible in the query.
SELECT MM.*, ML.*, MR.* FROM microfinance_manufacturers AS MM
INNER JOIN manufacturer_loans AS ML ON MM.ManufacturerId = Ml.ManufacturerId
INNER JOIN manufacturer_refunds AS MR ON MM.ManufacturerId = MR.manufacturerId
WHERE 1 = 1
ManufacturerId FirstName LastName Gender Religion PhoneNumber EmailAddress Notes CustomerAddedDateTime manufacturerTypeId manufacturerRoles LoanID ManufacturerId LoanAmount LoanDate RefundId manufacturerId RefundAmount RefundDate
5 Saud Jibran 0 0 8475983748G HFDKJFH VGHJXGVHJD 2015-04-29 14:12:20 21 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 6 5 65644343:1:"2015-05-06Em 6 5 77744s_Station2015-05-06:{
5 Saud Jibran 0 0 8475983748G HFDKJFH VGHJXGVHJD 2015-04-29 14:12:20 21 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 13 5 543543;s:1:"2015-05-07Em 6 5 77744s_Station2015-05-06:{
7 Naveed Ahmed 0 0 847893 hfkjhfskj fjksddshkfjdshfkj 2015-04-29 14:22:16 19 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 16 7 8798u656:1:"2015-05-07Em 9 7 4354334Station2015-05-07:{
7 Naveed Ahmed 0 0 847893 hfkjhfskj fjksddshkfjdshfkj 2015-04-29 14:22:16 19 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 16 7 8798u656:1:"2015-05-07Em 10 7 896789798ation2015-05-07:{
7 Naveed Ahmed 0 0 847893 hfkjhfskj fjksddshkfjdshfkj 2015-04-29 14:22:16 19 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 17 7 87987687:1:"2015-05-07Em 9 7 4354334Station2015-05-07:{
7 Naveed Ahmed 0 0 847893 hfkjhfskj fjksddshkfjdshfkj 2015-04-29 14:22:16 19 O:16:"clsEmployeeRoles":68:{s:56:"aEmployeeRole_Organization_RegionalHierarchy_RegionTypes";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:52:"aEmployeeRole_Organization_RegionalHierarchy_Regions";a:4:{i:0;i:0;i:1;i:0;i:2;i:0;i:3;i:0;}s:69:"aEmployeeRole_Organization_RegionalHierarchy_Regions_RegionStatistics";a:2:{i:0;i:0;i:2;i:0;}s:82:"aEmployeeRole_Organization_RegionalHierarchy_Regions_ 17 7 87987687:1:"2015-05-07Em 10 7 896789798ation2015-05-07:{
I have attached the pic of the output i am getting...
tables are manufacturer,loan,refund, manufacutrerId is common in all tables.
now in the pic it shows repeated record as the manufacturer took loan 2 times but return amount 1 time.. but it repeats in refund column. Please Help !!!
This query should work:
SELECT ManufacturerId,FirstName,LA,RA, LA - RA as RemainingAmount FROM (SELECT MM.ManufacturerId,MM. FirstName,SUM(LoanAmount) as LA, SUM(RefundAmount) as RA FROM microfinance_manufacturers AS MM
INNER JOIN manufacturer_loans AS ML ON MM.ManufacturerId = Ml.ManufacturerId
INNER JOIN manufacturer_refunds AS MR ON MM.ManufacturerId = MR.manufacturerId
GROUP BY MM.ManufacturerId) as a
You need to do the aggregations before the join. Otherwise, you end up with a cartesian product that throws off the values:
SELECT MM.*, ML.*, MR.*
FROM microfinance_manufacturers MM left join
(select Ml.ManufacturerId, count(*) as numloans, sum(ml.amount) as loanamount
from manufacturer_loans ML
group by ManufacturerId
) ml
on MM.ManufacturerId = Ml.ManufacturerId left join
(select Mr.ManufacturerId, count(*) as numrefunds, sum(ml.amount) as refundamount
from manufacturer_refunds mr
group by ManufacturerId
) mr
on MM.ManufacturerId = MR.manufacturerId;
Your question is unclear both on the data layout and on the expected results. But this should be basically what you need.

How to build this query?

i have table
http://oi58.tinypic.com/2s7xreo.jpg
id action_date type item_id quantity
--- ----------- ---- ------- --------
87 4/25/2014 1 s-1 100
88 4/1/2014 1 s-1 150
89 4/4/2014 1 s-1 200
90 4/3/2014 1 s-2 222
91 4/7/2014 1 s-2 10
96 4/4/2014 1 s-2 8
97 4/22/2014 1 s-2 8
98 4/21/2014 2 s-1 255
99 4/5/2014 2 s-1 6
100 4/6/2014 2 s-2 190
101 4/6/2014 2 s-3 96
102 4/8/2014 2 s-1 120
103 4/15/2014 2 s-2 3
104 4/16/2014 2 s-2 3
type column which mean if 1 this is in item to my shop >>> if 2 this is out item from my shop >>
i need query to give me result like this
item in out net
s1 300 195 105
and so on >>
how to write query that give me this result >>
and if i must but them in tow table >> table for the in and table for the out if that help >>> how it build the query >
and thanx in advance :)
note :: i am work on access
One way to get the result is to use an aggregate function on an expression that conditionally returns the value of quantity, based on the value of type.
SELECT t.item
, SUM(CASE WHEN t.type = 1 THEN t.quantity ELSE 0 END) AS in_
, SUM(CASE WHEN t.type = 2 THEN t.quantity ELSE 0 END) AS out_
, SUM(CASE WHEN t.type = 1 THEN t.quantity ELSE 0 END)
- SUM(CASE WHEN t.type = 2 THEN t.quantity ELSE 0 END) AS net_
FROM mytable t
GROUP BY t.item
This approach works in Oracle, as well as MySQL and SQL Server.
(If you remove the SUM() aggregate function and the GROUP BY clause, you can see how that CASE expression is working. The query above gives the result you specified, this one is just a demonstration that helps "explain" how that query works.)
SELECT t.item
, CASE WHEN t.type = 1 THEN t.quantity ELSE 0 END AS in_
, CASE WHEN t.type = 2 THEN t.quantity ELSE 0 END AS out_
, t.*
FROM mytable t
UPDATE
Unfortunately, Microsoft Access doesn't support CASE expressions. But Access does have an iif function. The same approach should work, the syntax might be something like this:
SELECT t.item
, SUM(iif(t.type = 1, t.quantity, 0) AS in_
, SUM(iif(t.type = 2, t.quantity, 0) AS out_
, SUM(iif(t.type = 1, t.quantity, 0)
- SUM(iif(t.type = 2, t.quantity, 0) AS net_
FROM mytable t
GROUP BY t.item
SELECT item_id,
In_col,
Out_col,
(In_col - Out_col) AS Net
FROM
(SELECT item_id,
sum(CASE WHEN TYPE = 1 THEN quantity END) AS In_col,
sum(CASE WHEN TYPE = 2 THEN quantity END) AS Out_col
FROM TABLE
GROUP BY item_id) AS t1;
I hope this what you need.