I would like to get the following results from my query:
id_product_attribute | id_product | reference | name | total
12 | 1 | 234235 | product_name | 2
14 | 2 | 235435 | product_name | 7
16 | 3 | 235325 | product_name | 4
etc
but when I use this query:
select pa.id_product_attribute, p.id_product, pa.reference, cl.name, sum(od.product_quantity) as total
from ps_product_attribute pa
left join ps_order_detail od on od.product_attribute_id = pa.id_product_attribute
left join ps_product p on pa.id_product = p.id_product
left join ps_category_product cp on cp.id_product = p.id_product
left join ps_category_lang cl on cp.id_category = cl.id_category
where cp.id_category = 141 and cl.id_lang = 6;
it gives me only this results:
id_product_attribute | id_product | reference | name | total
12 | 1 | 234235 | product_name | 13
so in the 'total' column it shows me the total of all, instead of seperate per row.
can anyone tell me what I'm doing wrong in my query?
Your source data would help, but at the very least you forgot to GROUP BY at the end. With the current query, you should add;
GROUP BY pa.id_product_attribute, p.id_product, pa.reference, cl.name
With MySQL, you can choose to GROUP BY less columns and get a random selection of values in the other ones, but if possible, you should GROUP BY all columns that don't have aggregates (like SUM in this case) on them.
Aggregate functions should be used with GROUP BY CLAUSE
Related
I have this query in mySQL where I would like to sum the line product of each doctor but I dont know how to do it.
use avant_medical;
select
sales.doctor_id as DoctorID,
line_products.id as LineProductID,
line_products.name as LineProductName
from `doctors`
inner join `sales` on `doctors`.`id` = `sales`.`doctor_id`
inner join `inventories` on `sales`.`id` = `inventories`.`sale_id`
inner join `products` on `inventories`.`product_id` = `products`.`id`
inner join `line_products` on `products`.`lineProduct_id` = `line_products`.`id`
order by `doctors`.`id` asc;
lPID= lineProductID
|DrID|lPID |
| -- | ----|
| 1 | 7 |
| 1 | 6 |
| 1 | 6 |
| 1 | 7 |
| 1 | 7 |
| 1 | 7 |
| 1 | 6 |
This is how I want:
Doctor 1
lineID | quantity
7 | 4
6 | 3
I try this query only in mySQL
The keyword you are looking for is count, not sum. Summing would add up every lineProductID as if they where regular mathematical values, while counting will add up how many times a given lineProductID is found.
select
sales.doctor_id as DoctorID,
line_products.id as LineProductID,
line_products.name as LineProductName,
-- We count the number of occurrences of each line_product.id
COUNT(line_products.id) as LineProductQty
from `doctors`
inner join `sales` on `doctors`.`id` = `sales`.`doctor_id`
inner join `inventories` on `sales`.`id` = `inventories`.`sale_id`
inner join `products` on `inventories`.`product_id` = `products`.`id`
inner join `line_products` on `products`.`lineProduct_id` = `line_products`.`id`
-- Never forget to properly GROUP your aggregate functions, such as COUNT() or SUM()!
GROUP BY sales.doctor_id, line_products.id, line_products.name
order by `doctors`.`id` asc;
Since you didn't provided full schema to test this, I made a small, very artificial demo, but should be representative of how the query above works.
I am trying to create an SQL query that conditionally pulls data from multiple tables.
I have four tables:
orders
+------+------------+------------+
| id | date_added | currency |
+------+------------+------------+
| 1 | 2018-07-23 | 1 |
+------+------------+------------+
order_items
+------+------------+------------+---------------+---------------+
| id | order_id | price | product_id | product_type |
+------+------------+------------+---------------+---------------+
| 1 | 1 | 100.00 | 1 | ticket |
+------+------------+------------+---------------+---------------+
order_data
+------+--------------+---------------+
| id | order_id | ext_order_ref |
+------+--------------+---------------+
| 1 | 1 | ABC |
+------+--------------+---------------+
products
+------+------------+------------+
| id | date | product_id |
+------+------------+------------+
| 1 | 2020-03-12 | 1 |
+------+------------+------------+
| 2 | 2020-03-18 | 2 |
+------+------------+------------+
| 3 | 2020-03-20 | 3 |
+------+------------+------------+
I need to output orders with the following conditions:
Each order in a row with total (calculated from order items with matching order id)
The 'ext_order_ref' from the order_data table that matches that order
Only include order items that have a specific product type
Only include orders with products from a particular date range
Preferred output would look like this:
+------------+------------+--------------+
| order_id | total | ext_order_ref|
+------------+------------+--------------+
| 1 | 100 | ABC |
+------------+------------+--------------+
My current query is basically like this; please advise
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_ref
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_ref
RIGHT JOIN order_items
ON orders.id = order_items.order_id
LEFT JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
It almost works, but not quite. The date particularly is causing issue.
Thanks in advance!
First decide the driving table for the query and form the query based on the driving table.
Driving table is the one primary table from which other tables join.
More information on driving tables from askTom
In your case, the driving table is Orders table. You are switching between RIGHT OUTER JOIN and LEFT OUTER JOIN. This will cause confusion in the resultset.
I have modified the query. See whether it works.
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_id
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_id
LEFT OUTER JOIN order_items
ON orders.id = order_items.order_id
LEFT OUTER JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
I don't understand why you would want outer joins at all. If I follow the conditions correctly:
SELECT o.id as order_id,
SUM(oi.price) as total,
od.ext_order_id
FROM orders o INNER JOIN
order_data od
ON o.id = od.ext_order_id INNER JOIN
order_items oi
ON o.id = oi.order_id INNER JOIN
products p
ON oi.product_id = p.product_id
WHERE oi.product_type = 'ticket' AND
p.date >= '2020-03-12' AND
p.date < '2020-03-19'
GROUP BY o.id, od.ext_order_id;
Note the use of table aliases so the query is easier to write and read.
I have a 3 tables order, order_option, product_option
order
order_id | cus_name | cus_phone
-------------------------------
1 | Test-1 | 9876543211
2 | Test-2 | 9876543212
3 | Test-3 | 9876543213
4 | Test-4 | 9876543214
order_option
product_option_id | order_id
-------------------------------
11 | 1
12 | 1
13 | 2
14 | 4
15 | 3
product_option
product_id | product_option_id | sku | qty
------------------------------------------
1 | 11 | TS01 | 3
2 | 12 | TS02 | 2
3 | 13 | TS033 | 3
4 | 14 | TS023 | 3
Here I want to select order table and product_option table values with a where condition on the sku field.
i tried to join the query like below:
SELECT o.order_id, o.cus_name, o.cus_phone,po.sku,po.qty FROM order o
LEFT JOIN order_option op
ON (o.order_id = op.order_id)
LEFT JOIN product_option po
ON (op.product_option_id = po.product_option_id)
WHERE po.sku = "TS023"
But it's not showing the correct answer. I don't know what I have missed.
order is a reserved word, use backticks ``.
SELECT o.order_id, o.cus_name, o.cus_phone, po.sku, po.qty
FROM `order` o
LEFT JOIN order_option op ON o.order_id = op.order_id
LEFT JOIN product_option po ON op.product_option_id = po.product_option_id
WHERE po.sku = "TS023"
Output:
order_id cus_name cus_phone sku qty
4 Test-4 9876543214 TS023 3
SQL Fiddle: http://sqlfiddle.com/#!9/9b76b/2/0
Move the po condition from WHERE to ON to get true LEFT JOIN result:
SELECT o.order_id, o.cus_name, o.cus_phone,po.sku,po.qty FROM order o
LEFT JOIN order_option op
ON (o.order_id = op.order_id)
LEFT JOIN product_option po
ON (op.product_option_id = po.product_option_id)
AND po.sku = "TS023"
(When in WHERE, you'll get regular INNER JOIN result.)
#Matt is correct, here's another way of doing this.
SELECT o.order_id, o.cus_name, o.cus_phone, po.sku, po.qty
FROM `order` o, order_option op, product_option po
WHERE o.order_id = op.order_id
AND op.product_option_id = po.product_option_id
AND po.sku = "TSO23"
I have these three tables in my database:
tblCustomer (id,name,address)
tblLoan (id,customerId,LoanAmount,date)
tblPayment (id,customerId,ReceivedAmount,date)
I want to find the total loanAmount for a customer and how much they have paid.
I wrote this query:
SELECT c.fname, SUM(l.amount), SUM(p.amount)
FROM tblCustomer c
JOIN tblLoan l ON (l.customerId = c.id)
JOIN tblPayment p ON (p.customerId = c.id)
WHERE c.id = 3;
It returns results but they are incorrect.
First, as others have mentioned, your syntax is likely incorrect because you do not have matching column names, but you said you had incorrect results, so I would assume that's not your problem as you were able to run your query..
The problem that I think you are most likely having is that by joining the two tables together like that, rows appear twice for each customer. Am I correct in assuming that your 'incorrect' results are double what you would expect? Let me illustrate for those who don't understand. Consider this data set, with shortened column values:
tblCustomer:
| id | name |
+----+------+
| 1 | Adam |
| 2 | John |
| 3 | Jane |
tblLoan, and for simplicity we'll say the payment table looks the same:
| customerID | loanAmount |
+------------+------------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
| 3 | 300 |
| 2 | 200 |
If I perform the following query (without summing values, just getting the values I want:
SELECT c.id, c.name, l.loanAmount, p.receivedAmount
FROM tblCustomer c
JOIN tblLoan l ON l.customerid = c.id
JOIN tblPayment p ON p.customerid = c.id
WHERE c.id = 3;
It returns this result set:
| id | name | loanAmount | receivedAmount |
+----+------+------------+----------------+
| 3 | Jane | 100 | 100 |
| 3 | Jane | 100 | 300 |
| 3 | Jane | 300 | 100 |
| 3 | Jane | 300 | 300 |
So notice that because we're joining two tables based on a relationship to a third table, were actually creating a cartesian product which is causing the problem. So, what I recommend you do is use subqueries for these two tables. One subquery will pull the loan values, one the payment values, and you can join those together on the id value.
It will look like this:
SELECT t.id, t.totalLoan, w.totalReceived
FROM(SELECT c.id, SUM(l.loanAmount) AS totalLoan
FROM tblCustomer c
JOIN tblLoan l ON l.customerid = c.id
WHERE c.id = 3) t
JOIN(SELECT c.id, SUM(p.receivedAmount) AS totalReceived
FROM tblCustomer c
JOIN tblPayment p ON p.customerid = c.id
WHERE c.id = 3) w
ON t.id = w.id;
And this should give you the values you want. Here is what I tested on SQL Fiddle.
FYI, YOUR COLUMN NAMES ARE WRONG!!!
There is no such column named fname in table tblCustomer
There is no such column named amount in table tblLoan
There is no such column named amount in table tblPayment
You won't get the right result if you don't have the appropriate column names. Even when using aliases, your column name should be EXACTLY THE SAME as in your database table. That's because, you are aliasing TABLES in JOIN queries, not COLUMNS.
So, re-write your query in the following way:
SELECT c.name, SUM(l.LoanAmount), SUM(p.ReceivedAmount)
FROM tblCustomer c
JOIN tblLoan l ON l.customerId = c.id
JOIN tblPayment p ON p.customerId = c.id
WHERE c.id = 3
Note that there's no need to get brackets around the ON clause in JOIN.
I have two tables in a MySQL database like this:
PRODUCT:
product_id | product_name
-----------+-------------
1 | shirt
2 | pants
3 | socks
PRODUCT_SUPPLIER: (id is primary key)
id | supplier_id | product_id | part_no | cost
----+---------------+--------------+-----------+--------
1 | 1 | 1 | s1p1 | 5.00
2 | 1 | 2 | s1p2 | 15.00
3 | 1 | 3 | s1p3 | 25.00
4 | 2 | 1 | s2p1 | 50.00
5 | 2 | 2 | s2p2 | 10.00
6 | 2 | 3 | s2p3 | 5.00
My goal is a query that joins the tables and outputs a single row for each product joined with all fields from the corresponding supplier row with the lowest cost like this:
product_id | product_name | supplier_id | part_no | cost
-----------+---------------+---------------+------------+---------
1 | shirt | 1 | s1p1 | 5.00
2 | pants | 2 | s2p2 | 10.00
3 | socks | 2 | s3p3 | 5.00
At present I do have the following query written which seems to work but I'd like to know from any of the more experienced SQL users if there is a cleaner, more efficient or otherwise better solution? Or if there is anything essentially wrong with the code I have?
SELECT p.product_id, p.product_name, s. supplier_id, s.part_no, s.cost
FROM product p
LEFT JOIN product_supplier s ON
(s.id = (SELECT s2.id
FROM product_supplier s2
WHERE s2.product_id = p.product_id
ORDER BY s2.cost LIMIT 1));
I would run:
select p.product_id, p.product_name, s.supplier_id, s.part_no, s.cost
from product p
join product_supplier s
on p.product_id = s.product_id
join (select product_id, min(cost) as min_cost
from product_supplier
group by product_id) v
on s.product_id = v.product_id
and s.cost = v.min_cost
I don't see the point in an outer join. Is every product is on the product_supplier table? If not then the outer join makes sense (change the join to inline view aliased as v above to a left join if that is the case).
The above may run a little faster than your query because the subquery is not running for each row. Your current subquery is dependent and relative to each row of product.
If you want to eliminate ties and don't care about doing so arbitrarily you can add a random number to the end of the results, put the query into an inline view, and then select the lowest/highest/etc. random number for each group. Here is an example:
select product_id, product_name, supplier_id, part_no, cost, min(rnd)
from (select p.product_id,
p.product_name,
s.supplier_id,
s.part_no,
s.cost,
rand() as rnd
from product p
join product_supplier s
on p.product_id = s.product_id
join (select product_id, min(cost) as min_cost
from product_supplier
group by product_id) v
on s.product_id = v.product_id
and s.cost = v.min_cost) x
group by product_id, product_name, supplier_id, part_no, cost
If for some reason you don't want the random # to come back in output, you can put the whole query above into an inline view, and select all columns but the random # from it.