I have 3 tables:
SUPPLIERS:
id, name, address, suburb, state, phone, email, deleted
CUSTOMERS:
id, name, address, suburb, state, phone, email, deleted
ACCREDITED_SUPPLIERS:
id, supplier_id, customer_id
I want to display all SUPPLIERS and 'tag' those that are already linked in ACCREDITED_SUPPLIERS...
Here is my statement:
SELECT SQL_CALC_FOUND_ROWS s.id, s.name, s.suburb, s.state, s.phone, s.email, s.deleted,
IF( ac.customer_id = '220', 1, 0 ) AS accredited
FROM suppliers s
LEFT OUTER JOIN accredited_suppliers ac ON ac.supplier_id = s.id
WHERE s.deleted='0'
ORDER BY s.name
This statement only returns 10 'tagged' rows
For some reason it is missing 3 rows inexplicably!
SELECT *
FROM `accredited_suppliers`
WHERE `customer_id` = '220'
RETURNS: 13 rows
Is my statement above correct? Am I issuing it correctly?
Don't you just want:
select
s.id AS supplier_id,
IF(a.supplier_id IS NULL, 0, 1) AS accredited
from
SUPPLIERS s
left join
ACCREDITED_SUPPLIERS a
ON
s.id = a.supplier_id AND
a.customer_id = 220;
Related
I have these 4 tables:
Suppliers(id_sup, name, city)
Companies( id_co, name, city)
Products(id_p, name, city)
Deliveries (id_sup, id_co, id_p)
in one query, I need to get a list of all cities (no duplicates) and for each, show the number of suppliers, companies, and products that can be found in that city.
In oracle SQL I would have used some Full OUTER JOIN. what's the alternative?
This is a suggested solution for joining 2 of the tables:
SELECT city
, COUNT(DISTINCT id_sup) Suppliers
, COUNT(DISTINCT id_co) Companies
FROM ( SELECT COALESCE(s.city,c.city) city
, id_sup
, id_co
FROM Suppliers AS s
LEFT OUTER JOIN Companies AS c ON c.city = s.city
UNION
SELECT COALESCE(s.city,c.city) city
, id_sup
, id_co
FROM Suppliers AS s
RIGHT OUTER JOIN Companies AS c ON c.city = s.city ) AS union_query
GROUP BY city
How to add the final table Products to the mix?
With UNION get all the cities from all 3 tables and LEFT join to the results the 3 tables to finally aggregate:
select t.city,
count(distinct s.id_sup) counter_suppliers,
count(distinct c.id_co) counter_companies,
count(distinct p.id_p) counter_products
from (
select city from suppliers union
select city from companies union
select city from products
) t
left join suppliers s on s.city = t.city
left join companies c on c.city = t.city
left join products p on p.city = t.city
group by t.city
See a simplified demo.
Just use union all and group by:
select city, sum(is_supplier), sum(is_company),
sum(is_product), sum(is_delivery)
from ((select city, 1 as is_suppler, 0 as is_company, 0 as is_product, 0 as is_delivery
from suppliers
) union all
(select city, 0 as is_suppler, 1 as is_company, 0 as is_product, 0 as is_delivery
from companies
) union all
(select city, 0 as is_suppler, 0 as is_company, 1 as is_product, 0 as is_delivery
from products
) union all
(select city, 0 as is_suppler, 0 as is_company, 0 as is_product, 1 as is_delivery
from deliveries
)
) c
group by city;
Or, even more simply in MySQL:
select city, sum(which = 'supplier'), sum(which = 'company'),
sum(which = 'product'), sum(which = 'delivery')
from ((select city, 'suppler' as which from suppliers
) union all
(select city, 'company' as which from companies
) union all
(select city, 'product' as which from products
) union all
(select city, 'delivery' as which from deliveries
)
) c
group by city;
to get all cities, since we don't have a city table as a dimension, we can get the domain from each of the city columns from each of the three tables, and combine them with UNION set operator:
SELECT cs.city
FROM suppliers cs
GROUP BY cs.city
UNION
SELECT cc.city
FROM companies cc
GROUP BY cc.city
UNION
SELECT cp.city
FROM products cp
GROUP BY cp.city
That should get us a list of distinct city values that appear in the three tables.
We could take that set, and do outer join operations to the individual tables. But that has the potential to generate cross product... if there are three suppliers related to a city and four companies related to the same city, we would generate a resultset of twelve rows.
To fix that, we could get a count of DISTINCT primary key values.
Or, we can pre-aggregate the results in inline views, returning a single row per city. That avoids the problem of semi-cartesian products.
Let's reference the query above in an line view in another query. We will alias it ci. (If we had a dimension table city, we could reference that,)
Something like this:
SELECT ci.city
, IFNULL(np.cnt_,0) AS cnt_products
, IFNULL(nc.cnt_,0) AS cnt_companies
, IFNULL(ns.cnt_,0) AS cnt_suppliers
FROM ( /* inline view query */ ) ci
LEFT
JOIN ( SELECT p.city
, COUNT(1) AS cnt_
FROM products p
GROUP BY p.city
) np
ON np.city = ci.city
LEFT
JOIN ( SELECT c.city
, COUNT(1) AS cnt_
FROM companies c
GROUP BY c.city
) nc
ON nc.city = ci.city
LEFT
JOIN ( SELECT s.city
, COUNT(1) AS cnt_
FROM suppliers s
GROUP BY s.city
) ns
ON ns.city = ci.city
ORDER BY ci.city
(In place of /* inline view query */, use the SQL text from the first query, to generate the distinct list of city.)
I have 4 MySQL tables in my database:
Users (uid, name)
Shops (shopId, shopName)
Reviews (ReviewId, text, userId, shopId, rate, date)
TransactionHistory (transactionId, userId, shopId, Amount, date)
Users write their comments to shops in Reviews table. And user payment history in some shops is saved in the TransactionHistory table.
I need to select all users' reviews for some period in time if that users made payments in that shop at the same period in time.
Select userId, shopId, rate, text, date from Review where date between "01.01.2019" and "01.02.2019" where shopId in (select distinct(shopId) from Shops)
Select userId, shopId, date from TransactionHistory where date between "01.01.2019" and "01.02.2019"
So I have two result sets and some records have the same pair (userId, shopId) - that is what I want to get: all records from 1 SQL request, which pairs (userId, shopId) is present in 2 SQL query.
If I understood that right, all you need is a join statement like this one:
SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)
Here is the resource https://dev.mysql.com/doc/refman/8.0/en/join.html
On your case inside the on statement would be what you want to be equal.
Select userId, shopId, rate, text, date from Review r join TransactionHistory th on (r.userId == th.userId and r.shopId == th.shopId) where r.date between "01.01.2019" and "01.02.2019" where r.shopId in (select distinct(shopId) from Shops)
SELECT u.uid, u.name as userName, u.surname, s.name, rate, review, c.amount FROM `rsamazingapp.rsamazingapp.reviews` as r
INNER JOIN `rsamazingapp.cashbacks` as c ON (r.uid = c.uid and r.shop_id = c.shop_id)
INNER JOIN `rsamazingapp.shops` as s on (r.shop_id = s.shop_id)
INNER JOIN `rsamazingapp.users` as u on (r.uid = u.uid)
where r.shop_id in (select distinct shop_id from `rsamazingapp.shops`)
order by rate desc
Welcome,
I have 2 tables int_client AND int_client_bank.
In first important columns: client_id, firstname, lastname, country, email, status.
In the second: client_id, status.
I need to display all records: firstname, lastname, country, e-mail WHERE status='25' of the first column (except those records where client_id occurs in the second table).
If client_id occurs in the second table is skipping statuses of the first column, and displays only status='25' in secound table.
Sb can help me?
edit:
SELECT firstname, lastname, country, email, COALESCE(b.status, a.status) status
FROM int_client a
LEFT JOIN int_client_back b USING (client_id)
WHERE
(b.status IS NULL and a.status='25')
OR b.status IS NOT NULL;
This is good code, but i need show only records there have status='25' in column B, and if a.client_id != b.client_id, i need show records there have status='25' in column A
Sb, help?
LEFT JOIN with COALESCE() should do:
SELECT firstname, lastname, country, email, COALESCE(b.status, a.status) status
FROM int_client a
LEFT JOIN int_client_back b USING (client_id)
WHERE
(b.status IS NULL and a.status='25')
OR b.status IS NOT NULL;
This select query should work:
SELECT t1.first_name,t1.last_name,t1.country,t1.email FROM int_client AS t1, int_client_bank AS t2
WHERE t1.client_id = t2.client_id AND t1.status = 25;
If I understand correctly, you want all records from int_client where status is "25". However, if another status exists in int_client_bank, then you want to show that status.
select c.first_name, c.last_name, c.email, c.country,
coalesce(cb.status, c.status)
from int_client c left join
int_client_bank cb
on cb.client_id = c.client_id
where c.status = 25;
Below is the query which will do the trick for you.
SELECT client_id, firstname, lastname, country, email, status FROM int_client as ic LEFT JOIN int_client_back icb ON ic.client_id=icb.client_id WHERE ic.status=25
SELECT DISTINCT firstname, lastname, country, email,
a.status as status_a, b.status as status_b, if(b.status is NULL, a.status, b.status) as final_status
FROM int_client a
LEFT JOIN int_client_bank b USING (client_id)
WHERE
if(b.status is NULL, a.status, b.status) = '25'
I have a query problem with count. I want to have a column with the number of persons registered to the course.
So far, this is my query:
select
courses.id,
name,
location,
capacity,
(
SELECT count(courses_requests.IDcourse)
FROM courses_requests, courses
WHERE courses_requests.IDcourse = courses.id AND status != "rejected"
) as Registered,
begin_date,
end_date,
price,
active
from courses
But this is giving me problems, it displays the same value for all rows, even if the course doesn't have persons registered in the course
E.G
Capacity Registered
2 1
30 1
It may be simplier to aggregate the outer select, to eliminate the subquery, so something like:
SELECT c.id,
c.name,
c.location,
c.capacity,
COUNT(cr.IDcourse) AS RequestCount
c.begin_date,
c.end_date,
c.price,
c.active
FROM courses c
INNER JOIN courses_requests cr
ON cr.IDcourse = c.id
AND status != "rejected"
GROUP BY c.id,
c.name,
c.location,
c.capacity,
c.begin_date,
c.end_date,
c.price,
c.active
You should connect your subquery to main query:
select courses.id,
courses.name,
courses.location,
courses.capacity,
(SELECT count(courses_requests.IDcourse)
FROM courses_requests,
WHERE courses_requests.ID = courses.id
and status != "rejected" ) as Registered,
begin_date,
end_date,
price,
active
from courses
You can use join to simplify your query ans using SUM() with a condition will give you the count
select
c.id,
c.name,
c.location,
c.capacity,
SUM(cr.status != "rejected") as Registered,
c.begin_date,
c.end_date,
c.price,
c.active
from courses c
JOIN courses_requests cr ON (cr.IDcourse = c.id)
GROUP BY c.id
The trouble I've been having with union is that the tables your querying must have all the same columns. Is there a way to query using an join with a union on ONLY certain coloumns?
SELECT Client.Client_ID, Client.First_Name, Client.Last_Name, Client.Company_Name from Client
union
select Agency_Employee.Employee_ID, Agency_Employee.First_Name, Agency_Employee.Last_Name, ''
from Agency_Employee
union
select Agency_ID, '', '', Agency_Name from Admin_Agency
SELECT proj.ProjectID, A.Project_Title, B.Account_ID, B.Username, B.Access_Type FROM Project_Assigned proj
JOIN Account B
ON proj.AccountID = B.Account_ID
JOIN Project A
ON proj.ProjectID = A.Project_ID
WHERE proj.ProjectID = 1;
In the above above I'm trying to combine a join query created which matches accounts assigned to project 1 and with union I'm trying to get additional information such as first_name, last_name from those account numbers from different tables such as client, agency_employee.
Yes it is.
You can do it by specifying the names of the columns- they should be the same.
In your case you can do it like that:
SELECT Client.Client_ID, Client.First_Name, Client.Last_Name, Client.Company_Name from Client
union
select Agency_Employee.Employee_ID as Client_ID, Agency_Employee.First_Name, Agency_Employee.Last_Name, '' as Company_Name
from Agency_Employee
union
select Agency_ID as Client_ID, '' as First_Name, '' as Last_Name, Agency_Name as Company_Name from Admin_Agency
I don't see in your code how exactly you want to merge your union with the following queries but you can do it with sub-queries. Here is the example:
select a.item1, b.count from table_a a
inner join (
select item1, count(*) as count
from table_b
group by item1
) b on b.item1 = a.item1