Join on same column name - mysql

Hello there I want to get data from two tables that share same column name. My table structure are
Table patients
---------------------------------------
| id | affiliate_id | somecolumn |
---------------------------------------
| 1 | 8 | abc |
---------------------------------------
| 2 | 8 | abc |
---------------------------------------
| 3 | 9 | abc |
---------------------------------------
Table Leads
---------------------------------------
| id | affiliate_id | someothern |
---------------------------------------
| 1 | 8 | xyz |
---------------------------------------
| 2 | 8 | xyz |
---------------------------------------
| 3 | 3 | xyz |
---------------------------------------
Now my requirement was to get COUNT(ID) from both tables in a single query. I want result like
----------------------------------------------------
| affiliate_id | total_patients | total_leads |
----------------------------------------------------
| 8 | 2 | 2 |
----------------------------------------------------
| 9 | 1 | 0 |
----------------------------------------------------
| 3 | 0 | 1 |
----------------------------------------------------
I wrote following query
SELECT `p`.`affiliate_id`, COUNT(p.id) AS `total_patients`,
COUNT(cpl.id) AS `total_leads`
FROM `patients` AS `p`
INNER JOIN `leads` AS `cpl` ON p.affiliate_id =cpl.affiliate_id
GROUP BY `p`.`affiliate_id`
But I am not getting result . This query results giving only one affiliate with same number of total_patients and total_leads

The problem is that you need to get a list of the distinct affiliate_id first and then join to your other tables to get the result:
select a.affiliate_id,
count(distinct p.id) total_patients,
count(distinct l.id) total_leads
from
(
select affiliate_id
from patients
union
select affiliate_id
from leads
) a
left join patients p
on a.affiliate_id = p.affiliate_id
left join leads l
on a.affiliate_id = l.affiliate_id
group by a.affiliate_id;
See SQL Fiddle with Demo

Two ways:
Select l.affiliate_id ,
count(distinct p.id) patientCount,
count(distinct l.id) LeadCOunt
From patients p Join leads l
On l.affiliate_id = p.Affiliate_id
Group By l.affiliate_id
or, (assuming affiliates are in their own table somewhere)
Select Affiliate_id,
(Select Count(*) From Patients
Where Affiliate_id = a.Affiliate_id) patientCount,
(Select Count(*) From Leads
Where Affiliate_id = a.Affiliate_id) LeadCount
From affiliates a

Related

Find the number of users who made their first order in each country, each day

I have 2 tables which looked like:
user_dataset
+------+---------------+------------+
|userid| Register_time | Country |
+------+---------------+------------+
| 1 | 03/02/17 | TW |
| 2 | 20/03/17 | SG |
| 3 | 26/03/17 | PH |
| 4 | 05/02/17 | VN |
| 5 | 01/10/17 | ID |
| 6 | 03/09/17 | MY |
| ...| ........ | ... |
+------+---------------+------------+
order_dataset
+--------+--------+------------+--------+------------+
|orderid | userid | itemid | gmv | order_time |
+--------+--------+------------+--------+------------+
|1030132 | 3 | 3366770 | 27,0 | 24/04/17 |
|1030137 | 5 | 6130641 | 69,0 | 02/02/17 |
|1030147 | 1 | 6770063 | 87,0 | 25/04/17 |
|1030153 | 6 | 4193426 | 82,0 | 05/11/17 |
|1030155 | 4 | 8825994 | 29,0 | 03/07/17 |
|1030160 | 2 | 5660916 | 44,0 | 30/01/17 |
|....... | ... | ... | ... | ... |
+--------+--------+------------+--------+------------+
I have been told to Write a SQL statement to find the number of users who made their first order in each country, each day.
I don't understand the question, can someone explain to me what the output looks like? I'm not asking the Queries but if someone willing to write it would be wonderful tho.
Thank you in advance
Join the table user_dataset to a query that returns from order_dataset the date of the 1st order of each userid and aggregate:
select u.country, o.order_time, count(*) counter
from user_dataset u inner join (
select userid, min(order_time) order_time
from order_dataset
group by userid
) o on o.userid = u.userid
group by u.country, o.order_time
If there is a case a user has placed 2 orders at the same day, then instead of count(*) use count(distinct userid).
SELECT a.userid, a.purchase_time,c.country
FROM purchase_tab a
INNER JOIN
(SELECT userid, MIN(purchase_time) As first_occurence
FROM purchase_tab
GROUP BY userid) b
ON a.userid = b.userid AND a.purchase_time = b.first_occurence
INNER JOIN user_tabs c
ON a.userid=c.userid
ORDER BY a.userid
SELECT
country,
order_time,
COUNT(*)
FROM user u
LEFT JOIN(
SELECT
userid,
MIN(order_time) AS min_date
FROM order
GROUP BY userid
) o
ON u.userid = o.userid
LEFT JOIN order ot
ON u.userid = ot.userid
WHERE order_time = min_date
GROUP BY country, order_time
ORDER BY country;

When I use "WHERE user_id in ( sub query )" generate syntax error

I have a users table used below.
Users have referal_code, refered_by columns.Users has following data.
+----+--------------+------------+
| id | referal_code | refered_by |
+----+--------------+------------+
| 1 | abc | null |
| 2 | xxx | abc |
+----+--------------+------------+
I have Reviews table in which I store users reviewe by other users.
It does have user_id, evaluation columns.
+----+---------+------------+
| id | user_id | evaluation |
+----+---------+------------+
| 28 | 2 | 4 |
| 32 | 2 | 6 |
+----+---------+------------+
I'm trying to count users referred by each user have an average evaluation of 3 or more.
SELECT users.*, COUNT(
SELECT reviews.user_id FROM reviews
WHERE reviews.user_id IN(
SELECT A2.id FROM users as A2 WHERE A2.refered_by = users.referal_code
)
HAVING AVG(evaluation) >= 3) as total_3_estrelas
FROM users
WHERE 1
I have a syntax error #1064 on: WHERE user_id IN
The result I expect:
+----+--------------+------------+------------------+
| id | referal_code | refered_by | total_3_estrelas |
+----+--------------+------------+------------------+
| 1 | abc | null | 1 |
| 2 | xxx | abc | 0 |
+----+--------------+------------+------------------+
Look at this if it helps:
SELECT A.ID, A.REFERAL_CODE, A.REFERED_BY, COALESCE(TOTAL_3_ESTRELAS,0) AS TOTAL_3_ESTRELAS
FROM USERS A
LEFT JOIN
(SELECT REFERED_BY, COUNT(*) AS TOTAL_3_ESTRELAS
FROM USERS U
INNER JOIN (SELECT USER_ID, AVG(EVALUATION)
FROM REVIEWS
GROUP BY USER_ID
HAVING AVG(EVALUATION)>=3) R
ON U.ID=R.USER_ID
GROUP BY REFERED_BY) T
ON A.REFERAL_CODE=T.REFERED_BY;
From the deeper nested condition, first I calculated the average evaluation for each user_id on REVIEWS throwing away USER_ID with avg below 3, then I made the inner join with USERS and I grouped by REFERED_BY to obtain the count desired. Finally I did a left join to obtain the output in the form you expect.

how to perform an outer join in mysql

I have a table A that contains tree columns, id, users ids and vehicle id. And a table B that contains vehicleid, and vehicle name.
Table A
---------------------------
| Id | User_id |Vehicle_id|
---------------------------
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 2 | 2 |
| 5 | 2 | 3 |
| 6 | 4 | 5 |
---------------------------
Table B
-------------------
| Id |Vehicle_name|
-------------------
| 1 | Car |
| 2 | Bike |
| 3 | Plane |
| 4 | Boat |
| 5 | Rocket |
-------------------
Given a user id, I need to get all vehicle names, that doesn't match with table A. I've tried Outer joins, but I can't manage to do get the info that i need.
For example: Given user id 1, the query should return Car and Rocket.
thanks in advance
This is simple enough using not in or not exists:
select b.*
from b
where not exists (select 1
from a
where a.vehicle_id = b.id and a.user_id = #a_user_id
);
I also thought of using a cross join and was able to get the output in case you are more comfortable with join logic.
SELECT CJOIN.USER_ID, CJOIN.VEHICLE_ID, CJOIN.VEHICLE_NAME
FROM
(SELECT DISTINCT A.USER_ID, B.ID AS VEHICLE_ID, B.VEHICLE_NAME FROM TABLE_A A CROSS JOIN TABLE_B B) CJOIN
LEFT JOIN
TABLE_A D
ON CJOIN.USER_ID = D.USER_ID AND CJOIN.VEHICLE_ID = D.VEHICLE_ID
WHERE D.USER_ID IS NULL AND D.VEHICLE_ID IS NULL;
First, I got all possible combinations of USER_ID x VEHICLE_ID by a cross join and used this table in a left join to pull records for which there is no match.

MySQL GroupBy with null/zero results

I'm currently writing a ticket system that has three tables
one for users:
users
+----+-----------+----------+
| ID | FirstName | LastName |
+----+-----------+----------+
| 1 | First | User |
| 2 | Second | User |
| 3 | Third | User |
| 4 | Fourth | User |
| 5 | Fifth | User |
+----+-----------+----------+
one for tickets:
ticket
+----+---------------+
| ID | TicketSubject |
+----+---------------+
| 1 | Ticket #1 |
| 2 | Ticket #2 |
| 3 | Ticket #3 |
| 4 | Ticket #4 |
+----+---------------+
and one to assign users to tickets to action (can be more than one user per ticket):
ticket_assigned
+----+----------+--------+
| ID | TicketID | UserID |
+----+----------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 3 | 5 |
| 5 | 3 | 3 |
+----+----------+--------+
I'm trying to create a summary to show each user, and how many tickets they have assigned to them, example:
+------------+-------+
| Name | Count |
+------------+-------+
| First | 2 |
| Second | 1 |
| Third | 1 |
| Fourth | 0 |
| Fifth | 1 |
| Unassigned | 2 |
+------------+-------+
Note that the last entry is "unassigned", this is the number of records in the ticket table that DONT appear in the ticket_assigned table (thus being, unassigned). Also further note that user "Fourth" is zero, in that that user has no records in the ticket_assigned table.
Here is the current MySQL query I am using:
SELECT
CASE
WHEN users.FirstName IS NULL
THEN 'Unassigned'
ELSE users.FirstName
END as 'UserName',
COUNT(*) as 'TicketCount'
FROM tickets
LEFT OUTER JOIN ticket_assigned ON tickets.ticket_id = ticket_assigned.ticket_id
LEFT OUTER JOIN users ON ticket_assigned.user_id = users.user_id
GROUP BY ticket_assigned.user_id
ORDER BY UserName;
Problem with this is that it's not showing any of the users that don't feature in the ticket_assigned table, I'm essentially getting this:
+------------+-------+
| Name | Count |
+------------+-------+
| First | 2 |
| Second | 1 |
| Third | 1 |
| Fifth | 1 |
| Unassigned | 2 |
+------------+-------+
Is anyone able to assist and tell me how I can modify my query to include users that have no records in the ticket_assigned table? Thanks in advance!
Use a LEFT JOIN with a subquery to aggregate tickets:
SELECT t1.FirstName,
COALESCE(t2.ticket_count, 0) AS num_tickets
FROM users t1
LEFT JOIN
(
SELECT UserID, COUNT(*) AS ticket_count
FROM ticket_assigned
GROUP BY UserID
) t2
ON t1.ID = t2.UserID
UNION ALL
SELECT 'Unassigned', COUNT(*)
FROM tickets t
WHERE NOT EXISTS (SELECT 1 FROM tickets_assigned ta
WHERE ta.ticketId = t.id)
In MySQL, I think you need a left join and union all:
select u.id, u.firstname, count(ta.userId) as num_tickets
from users u left join
tickets_assigned ta
on ta.userId = u.id
group by u.id, u.firstname
union all
select NULL, 'Unassigned', count(*)
from tickets t
where not exists (select 1
from tickets_assigned
where ta.ticketId = t.id
);
I included the u.id in the aggregations. I'm uncomfortable just aggregating (and reporting) by first name, because different people frequently have the same first name, even in a relatively small group.
SELECT
u2.Firstname, IFNULL(tmp.count, 0) AS count
FROM users u2
LEFT JOIN (
SELECT u.id, u.Firstname, COUNT(1) as count
FROM ticket_assigned ta
LEFT JOIN ticket t ON t.id = ta.ticketID
LEFT JOIN users u ON u.id = ta.userID
GROUP BY u.id
) tmp ON tmp.id = u2.id
UNION
SELECT
'Unassigned', count(1) AS count
FROM ticket
WHERE id NOT IN (SELECT ticketid FROM ticket_assigned)

many-to-many and many-to-many intersections

Say I have a database that has people, grocery stores, and items you can buy in the store, like so:
Stores People Foods
----------------- ------------------ ------------------
| id | name | | id | name | | id | name |
----------------- ------------------ ------------------
| 1 | Giant | | 1 | Jon Skeet | | 1 | Tomatoes |
| 2 | Vons | | 2 | KLee1 | | 2 | Apples |
| 3 | Safeway | ------------------ | 3 | Potatoes |
----------------- ------------------
I have an additional table which keep track of which stores sell what:
Inventory
--------------------
| store_id| food_id|
--------------------
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
--------------------
And I have another table that has shopping lists on it
Lists
---------------------
| person_id| food_id|
---------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 3 |
---------------------
My question is, given a person, or their id, what is the best way to figure out what stores they can go to so they will get everything on their list. Is there a pattern for these types of computations in MySQL?
My attempt (very ugly and messy) is something like:
-- Given that _pid is the person_id we want to get the list of stores for.
SELECT stores.name, store_id, num, COUNT(*) AS counter
FROM lists
INNER JOIN inventory
ON (lists.food_id=inventory.food_id)
INNER JOIN (SELECT COUNT(*) AS num
FROM lists WHERE person_id=_pid
GROUP BY person_id) AS T
INNER JOIN stores ON (stores.id=store_id)
WHERE person_id=_pid
GROUP BY store_id
HAVING counter >= num;
Thanks for your time!
Edit SQL Fiddle with Data
If I were to solved the problem, I'll join the four tables with their linking column (specifically the foreign keys) then a subquery on the HAVING clause to count the number of items on the list for each person. Give this a try,
SET #personID := 1;
SELECT c.name
FROM Inventory a
INNER JOIN Foods b
ON a.food_id = b.id
INNER JOIN Stores c
ON a.store_id = c.id
INNER JOIN Lists d
ON d.food_id = b.id
WHERE d.person_id = #personID
GROUP BY c.name
HAVING COUNT(DISTINCT d.food_id) =
(
SELECT COUNT(*)
FROM Lists
WHERE person_ID = #personID
)
SQLFiddle Demo
#JohnWoo: why DISTINCT?
Another one...
SET #pid=2;
SELECT store_id, name
FROM inventory
JOIN lists ON inventory.food_id=lists.food_id
JOIN stores ON store_id=stores.id
WHERE person_id=#pid
GROUP BY store_id
HAVING COUNT(*)=(
SELECT COUNT(*)
FROM lists
WHERE person_id=#pid
);