I have 2 tables, products and origins
Products:
p_id | name | origin_id
------------------------
1 | P1 | 1
2 | P2 | 2
3 | P3 | 1
Origins:
o_id | name
-------------
1 | O1
2 | O2
I am using the following query :
SELECT * FROM `products` LEFT OUTER JOIN `origins`
ON ( `products`.`origin_id` = `origins`.`o_id` ) LIMIT 2
I am getting the below results
p_id | name | origin_id | o_id | name
-----------------------------------------
1 | P1 | 1 | 1 | O1
3 | P3 | 1 | 1 | O1
I was wondering how the LEFT OUTER JOIN affects the result where I am getting the first and the third row rather than the first and the second row?
When you are not using ORDER BY Clause, there is no guarantee of a specific order for your SELECT query.
So we should use ORDER BY when we need any specific order.
See this: MySQL Ref: What is The Default Sort Order of SELECT with no ORDER BY Clause
You don't control the inherent ordering of rows in a table. It behaves like a set. If you want to order it, use order by clause.
SELECT * FROM `products` p LEFT OUTER JOIN `origins` o
ON ( p.`origin_id` = o.`o_id` ) ORDER BY p.`name` LIMIT 2
Output :
p_id | name | origin_id | o_id | name
-----------------------------------------
1 | P1 | 1 | 1 | O1
2 | P2 | 2 | 2 | O2
Related
I am trying to get multiple rows with mysql join but if one of the rows doesn't meet the search condition didn't get it.
example :
I have a products table and orders table and order_products table
when someone order like 2 products I insert the order information in the order table and insert every product with its quantity in order_products table with order id
this is the schema I have
products table
| id | title |
---------------
| 1 | p1 |
| 2 | p2 |
| 3 | p3 |
| 4 | p4 |
Orders table
| id | client |
---------------
| 1 | c1 |
| 2 | c2 |
| 3 | c3 |
order_products table
| id | order_id| product_id |
-----------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 4 |
| 4 | 3 | 3 |
my query is
SELECT `orders`.*, GROUP_CONCAT(`products`.`title` SEPARATOR ' ') AS products FROM `orders` LEFT JOIN `order_products` ON `order_products`.`order_id` = `orders`.`id` LEFT JOIN `products` ON `products`.`id` = `order_products`.`product_id` GROUP BY `orders`.`id`
this query is working fine and as I intended to but the problem is when I search by product title example p1
the result I got
| id | client | info |
-------------------------
| 1 | c1 | p1 |
| 2 | c2 | p1 |
the result I want to get is like this even if the product p2 doesn't appear in search but it's in the order and I am selecting orders not products
| id | client | products|
-------------------------
| 1 | c1 | p1 p2 |
| 2 | c2 | p1 |
You want to use a having clause, not a where clause:
SELECT o.*, GROUP_CONCAT(p.title SEPARATOR ' ') AS products
FROM orders o JOIN
order_products op
ON op.order_id = o.id JOIN
products p
ON p.id = op.product_id
GROUP BY o.id
HAVING SUM( p.title LIKE ? ) > 0;
The ? is a parameter placeholder for what you are looking for.
This returns all products for orders that contain the product you are interested in.
Note the other changes I made to the query:
I introduced table aliases, so the query is easier to write and to read.
I removed the backticks, for the same reason.
I changed the LEFT JOIN to JOIN because an outer join is not necessary. Your logic requires at least one match to a product.
I have written a query to get the items from the table which doesn't have any child items. It's working fine but is very slow.
Any better/easier/optimized way to write the same thing?
select distinct id, (select count(i.item_id) from order_item as i where i.parent_item_id = o.item_id) as c
from order_item as o
where product_type = 'bundle'
having c = 0
order by id desc
limit 10;
Few of the fields are these to get the idea of a structure
Table: order_item
Columns:
item_id PK
order_id
parent_item_id
product_id
product_type
item_id | order_id | parent_item_id | product_id | product_type
-----------------------------------------------------------------
1 | 1 | null | 1 | bundle
2 | 1 | 1 | 2 | simple
3 | 1 | 1 | 3 | simple
4 | 1 | null | 4 | bundle
5 | 2 | null | 1 | bundle
6 | 2 | 5 | 2 | simple
7 | 2 | 5 | 3 | simple
Query should only return the 4rth item
Try below. Also consider creating indexes on PARENT_ITEM_ID and ITEM_ID
SELECT OI.*
FROM ORDER_ITEM OI
LEFT JOIN ORDER_ITEM OI2
ON OI2.PARENT_ITEM_ID = OI.ITEM_ID
WHERE OI.PRODUCT_TYPE = 'bundle' AND OI2.PARENT_ITEM_ID IS NULL
I would suggest not exists:
select oi.*
from order_item oi
where oi.product_type = 'bundle' and
not exists (select 1
from order_item oi2
where oi2.parent_item_id = oi.item_id and oi2.product_type = 'bundle'
)
order by id desc
limit 10;
For performance, you want an index on order_item(parent_item_id, product_type).
Note: I'm not sure you want the product_type filter in the subquery, but it is the logic your query is using.
Having these 2 tables (from inventory functionalities)
SQL Fiddle
-- ins table
+------+-------------+-------------+
| id | direction | quantity |
+------+-------------+-------------+
| 1 | in | 5 |
| 2 | in | 3 |
+------+-------------+-------------+
-- outs table
+------+-------------+-------------+
| id | direction | quantity |
+------+-------------+-------------+
| 1 | out | 4 |
| 2 | out | 1 |
| 3 | out | 2 |
| 4 | out | 1 |
+------+-------------+-------------+
How can I join rows from outs table to a row from ins table that has quantity covers/equals to the quantities of the outs rows that joined it, in other words how to get a result like this ?
-- result
+------+-------------+-------------+------+-------------+-------------+
| id | direction | quantity | id | direction | quantity |
+------+-------------+-------------+------+-------------+-------------+
| 1 | out | 4 | 1 | in | 5 |
| 2 | out | 1 | 1 | in | 5 |
| 3 | out | 2 | 2 | in | 3 |
| 4 | out | 1 | 2 | in | 3 |
+------+-------------+-------------+------+-------------+-------------+
as you can see rows 1,2 from outs table is taken from/ joined to row 1 from ins table and rows 3,4 from outs table is taken from/ joined to row 2 from ins table
NOTE: the quantities in the 2 tables are guaranteed to be sealed (a row from ins table is always has quantity that is exactly equal to 1 or more quantities of rows from table outs)
I wish I can just do something like this
-- sedu SQL
SELECT
whatever
FROM
outs left join
ins on outs.quantity <= (ins.quantity - previously joined outs.quantities);
This is painful to do in MySQL for a couple of reasons. First, MySQL doesn't have very good support for cumulative sums, which is what you want to compare.
And second, your result set is a little bit weak. It makes more sense to show all the ins records that contribute to each outs record, not just one of them.
For this purpose, you can use a join on cumulative sums, which looks like this:
select o.*, (o.to_quantity - o.quantity) as from_quantity,
i.*
from (select o.*,
(select sum(o2.quantity)
from outs o2
where o2.id <= o.id
) as to_quantity
from outs o
) o join
(select i.*,
(select sum(i2.quantity)
from ins i2
where i2.id <= i.id
) as to_quantity
from ins i
) i
on (o.to_quantity - o.quantity) < i.to_quantity and
o.to_quantity > (i.to_quantity - i.quantity)
Here is the SQL Fiddle.
Subquery with correlation approach might also useful
select t.id, t.direction, t.quantity, i.id, i.direction, i.quantity
from (
select id, direction, quantity,
quantity + coalesce((select quantity from outs where id < o.id order by id desc limit 1),
(select quantity from outs where id > o.id order by id limit 1)) Qty
from outs o
)t inner join ins i on i.quantity = t.Qty
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.
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