Better way to use UNION - mysql

i have a table products that have 5 fields to supplier
code supplier_1 supplier_2 supplier_3
000001 3 87 25
000002 12 5 48
I have to bring the code of product and all suppliers that have relation with
For that i create a query of each supplier and relate then
like
select code supplier1
from products
union
select code supplier2
from products
... and so on
there is another way to do that ?

Starting in MySQL 8.0.14, you can use a lateral join:
select t.code, s.supplier
from t cross join lateral
(select supplier_1 as supplier union all
select supplier_2 as supplier union all
select supplier_3 as supplier union all
select supplier_4 as supplier
) s;

Related

MS Access SQL Query with grouping across rows and columns

I have a table in MS Access with following layout. I am using MS Access 2019
Category1 Qty1 Category2 Qyt2
================================
A 10 B 2
B 3 C 4
A 2 A 4
C 3 B 3
I want the output as
Category Qty
================
A 16
B 8
C 7
Please suggest how to achieve this using query in MS Access.
Thanks
Use UNIONALL and GROUP BY in inner sub query
HERE CHECK SQL Fiddle
SELECT Category, SUM(Qty) as Qty FROM (
SELECT Category1 AS Category, Qty1 AS Qty FROM TAB1
UNION ALL
SELECT Category2 as Category, Qty2 AS Qty FROM TAB2
) as TAB
GROUP BY TAB.Category
Rearrange data with UNION query into normalized structure should be in first place.
SELECT Category1 AS Cat, Qty1 AS Qty, 1 AS Src FROM tablename
UNION SELECT Category2, Qty2, 2 FROM tablename;
Use that query as source for an aggregate query.

How to query all records from multiple tables with joins

I have my main table employee_rates_year:
tier skill rate year
1 28 110 2019
2 28 101 2019
my column skill is connected to an employees table and subcontractors table, for simplicity here is a shortened version of tblEmployees:
EMPLOYEEID Skill FullName
1 28 Employee One
2 28 Employee Two
and tblSubcontractors:
SUBCONTRACTORID Skill FullName
1 28 Sub One
2 28 Sub Two
I am trying to get a tier, rate and year show up for every individual employee & subcontractor.
I've tried using different joins but nothing seems to give me information with every employee/subcontractor.
Here is my query:
SELECT *
FROM employee_rates_year
left join tblsubcontractors on employee_rates_year.skill = tblsubcontractors.skill
left join tblemployees on employee_rates_year.skill = tblemployees.skill
The problem is that my query shows results like this:
tier skill rate year tblEmployees.FullName tblSubcontractors.Fullname
1 28 110 2019 Employee One Sub One
2 28 101 2019 Employee Two Sub Two
Whereas I am trying to get:
tier skill rate year tblEmployees.FullName tblSubcontractors.FullName
1 28 110 2019 Employee One
1 28 110 2019 Sub One
2 28 101 2019 Employee Two
2 28 101 2019 Sub Two
I have also tried using WHERE to try and differentiate between the two tables and pick individual records.
you should never use SELECT *, because.... 😜
Try:
SELECT
tier,
skill,
rate,
year,
tblEmployees.FullName As Employee
'' As Subcontractor
FROM employee_rates_year
left join tblsubcontractors on employee_rates_year.skill = tblsubcontractors.skill
union all
SELECT
tier,
skill,
rate,
year,
'' As Employee
tblSubcontractors.Fullname As Subcontractor
FROM employee_rates_year
left join tblemployees on employee_rates_year.skill = tblemployees.skill
You seem to need UNION ALL and not a double join:
SELECT e.*, t.FullName EmployeesFullName, NULL SubcontractorsFullName
FROM employee_rates_year e
left join tblsubcontractors t on e.skill = t.skill
UNION ALL
SELECT e.*, NULL, t.FullName
FROM employee_rates_year e
left join tblemployees t on e.skill = t.skill
ORDER BY e.tier, e.skill
Each query of the 2 uses a join of employee_rates_year with 1 of the other tables.
Finally the 2 resultsets are merged with UNION ALL.
Think the problem (or part of the problem) is because of the "left join", which creates one row in result for each row in the "left" table. Since employee_rates_year only has two rows, your result for query will only have 2 rows.
Use a union all to bring the employees and subcontactors together and then join and group by. To get values in "vertical lists", you can use row_number():
select er.skill, er.rate, er.year,
max(e_fullname) as e_fullname,
max(s_fullname) as s_fullname
from ((select e.skill, e.fullname as e_fullname, null as s_fullname,
row_number() over (partition by e.skill order by e.fullname) as seqnum
from tblemployees e
) union all
(select s.skill, null as e_fullname, s.fullname as s_fullname,
row_number() over (partition by s.skill order by s.fullname) as seqnum
from tblsubcontractors s
)
) es left join
employee_rates er
on es.skill = er.skill
group by er.skill, er.rate, er.year, seqnum;
If you just want the values in separate lists (with NULLs), then you don't need the row_number() trick:
select er.skill, er.rate, er.year, e_fullname, s_fullname
from ((select e.skill, e.fullname as e_fullname, null as s_fullname
from tblemployees e
) union all
(select s.skill, null as e_fullname, s.fullname as s_fullname
from tblsubcontractors s
)
) es left join
employee_rates er
on es.skill = er.skill;

SUM 2 Field from 2 different tables

I have a mysql query like this :
SELECT SUM(bills.Amount) AS AmountExpense, SUM(assets.Amount) as AmountIncome
FROM bills, assets where bills.UserId = 11 and assets.UserId =11
Sample Bills table
id payee description UserId Amount
1 john advance 11 15.0
2 dave request 2 13.0
3 er request 11 12.0
Sample assets table
id payee description UserId Amount
1 john advance 11 40.2
2 dave request 2 13.0
3 ww request 11 14.00
I have a problem with AmountExpense, the record SUM record multiple time. I have successed with Amount Income. Any suggestions?
You have most likely more than one row per user on one or both of those tables. You'll need to join them after performing the aggregation. Also, please don't use old style non ANSI implicit joins:
SELECT AmountExpense, AmountIncome
FROM ( SELECT UserId,
SUM(Amount) AS AmountExpense
FROM bills
GROUP BY UserId) AS b
LEFT JOIN ( SELECT UserId,
SUM(Amount) AmountIncome
FROM assets
GROUP BY UserId) AS a
ON b.UserId = a.UserId
WHERE b.UserId = 11
If you have the possibility that users can be in either table, but not the other, then you want the equivalent of a full outer join. MySQL doesn't support that syntax, but it does support this:
select userid, sum(amountexpense) as amountexpense, sum(amountincome) as amountincome
from (select userid, amount as amountexpense, null as amountincome
from bills
union all
select userid, null, amount as amountincome
from assets
) ba
group by userid;

SQL Table Solution With Calculating Different Columns in Same Table

I have a sql table like :
id buy_product buy_product_total sell_product sell_product_total
1 apple 5
2 banana 8
3 cake 20
4 apple 1
5 cake 2
6 apple 2
My problem is, I want to show product name and how many product left. Like :
product_name left
apple 6
cake 18
How can I show like that solution with sql query ?
I create table as answerers as :
Buy Table
id product_name total
1 apple 5
2 banana 8
3 cake 20
4 apple 2
Sell Table
id product_name total
1 apple 1
2 cake 2
I want to table like this
product_name left
apple 6
banana 8
cake 18
Is not a good table, could be better that buy and sell to be the same collumn buy with positive values and sell with negative.
But answer your question, suppose that your table name is myTable,
obs: you can execute every select separeted to understand better
select buy_product as product_name, (buy_total - sell_total) as left
from (
(select buy_product, sum(buy_product_total) as buy_total
from myTable where buy_product_total is not null group by buy_product) as buy_list
inner join
(select sell_product, sum(sell_product_total) as sell_total
from myTable where sell_product_total is not null group by sell_product) as sell_list
on buy_list.buy_product = sell_list.sell_product
)
As others have noted, your table structure is less than optimal.
However, given what you have, this will give you the results you're after.
select product, sum(total) from
(
select buy_product as product, buy_product_total as total
from yourtable
where buy_product is not null
union
select sell_product, -sell_product_total
from yourtable
where sell_product is not null
) v
group by product
Or, with your two tables
select product_name, sum(total) from
(
select product_name, total
from buy_table
union
select product_name, -total
from sell_table
) v
group by product_name
You should consider a different database design that is more appropriate (You may want to read up on normalization), but query follows:
SELECT t1.buy_product_total - t2.sell_product_total
FROM ProductTable t1, ProductTable t2
WHERE t1.buy_product = t2.sell_product
i.e. You're joining the table to itself using a 'self join'...

need help to shorten mysql multiple OR conditions

I have a table which contains manager id and staff ids (comma separated) and i have the following sql statement:
SELECT manager_id, staff_ids
FROM manager_staffs
WHERE 1 IN (staff_ids)
OR 3 IN (staff_ids)
OR 5 IN (staff_ids)
OR 23 IN (staff_ids)
OR 12 IN (staff_ids)
OR 16 IN (staff_ids)
OR 19 IN (staff_ids)
OR 32 IN (staff_ids)
OR 123 IN (staff_ids)
............
basically, it is a very long query with a lot of 'OR' condition. I would like to improve or shorten it if there is a way.
need help from all the sql gurus.
The problem is your data structure - don't put all the staff ids in one column. Make a table - you can call it manager_staff:
CREATE TABLE manager_staff (
manager_id int,
staff_id int
);
And so you can make records that show which manager every staff person reports to. Then your query becomes:
select manager_id, staff_id from manager_staff where staff_id in (1,3,...);
Im not sure what are you trying to achieve but try this:
SELECT manager_id, staff_ids
FROM manager_staffs
WHERE staff_ids in ('1','3' and so on)
Assuming staff_ids is a comma separated field then you could do the following.
SELECT DISTINCT manager_id, staff_ids
FROM manager_staffs a
INNER JOIN (SELECT 1 AS staff_id UNION SELECT 3 UNION SELECT 5 UNION SELECT 23 UNION SELECT 12 UNION SELECT 16 UNION SELECT 19 UNION SELECT 32 UNION SELECT 123) b
ON FIND_IN_SET(b.staff_id, a.staff_ids) > 0
But as I commented earlier, splitting it up would be a far better idea
why dont you try this
SELECT manager_id, staff_ids
FROM manager_staffs
WHERE staff_ids IN (1,3,5,23,12,16,19,32,123,.......)
you have no choice how to reduce your ORs only if you create other table and select them like query above.
structure your table is best to get performance when retrieving data.
your table should look like that
manager_staff
manager_id , staff_id
1 1
1 3
1 5
1 23
..........