I would like to ask for help for an SQL request that give me values from two tables.
As an example I have one Table orders und one table processing.
I would like to make an report of the orders and the state of processing.
table orders
id | status | div
-------------------
1 | wating_r | div1
2 | closed | div2
3 | closed | div3
-
table processing:
id | order_id | type | date
----------------------------------------
1 | 2 | send_request | 15.01.15
2 | 2 | send_invoice | 30.01.15
3 | 1 | send_request | 01.02.15
4 | 3 | send_request2 | 10.02.15
5 | 3 | send_invoice | 15.02.15
what I would like to get:
order_id | status | date_request | date_request2 | date_invoice
--------------------------------------------------------------------------------
1 | waiting_r | 01.02.15 | NULL | NULL
2 | closed | 15.01.15 | NULL | 30.01.15
3 | closed | NULL | 10.02.15 | 15.02.15
my solution:
select orders.id as order_id, orders.status, IF(processing.type='send_invoice',date_format(processing.date, '%Y-%m-%d'), NULL) as date_invoice, IF(processing.type='send_request',date_format(processing.date, '%Y-%m-%d'), NULL) as date_request, IF(processing.type='send_request2',date_format(processing.date, '%Y-%m-%d'), NULL) as date_request2
from orders
inner join processing on orders.id = processing.order_id
where
case
when orders.status='closed' then processing.type='send_invoice'
when orders.status='waiting_r' then processing.type='send_request'
when orders.status='waiting_2'then processing.type='send_request2'
end
This works fine but with this IF statements I doesn't become the dates from the requests when an invoice was sent - I only get the date of the invoice.
Instead of the case request I tried the following but in this case I have more than one line for every order. When I tried to "group by" I have mixed data.
where
processing.type in ('send_invoice', 'send_request', 'completion_request_send')
You need to left-join the second table to the first three times, like so.
SELECT o.id AS order_id, o.status,
p1.date AS date_request,
p2.date AS date_request2,
p3.date AS date_invoice
FROM orders o
LEFT JOIN processing p1 ON o.id = p1.order_id AND p1.type='send_request'
LEFT JOIN processing p2 ON o.id = p2.order_id AND p2.type='send_request2'
LEFT JOIN processing p3 ON o.id = p3.order_id AND p3.type='send_invoice'
ORDER BY 1,2
This left-join with an id-matching criterion and the specific type choice pulls out the rows you need for each column. Left, as opposed to inner, join, allows the missing values to be shown as null.
Here it is, working. http://sqlfiddle.com/#!9/b8c74/5/0
This is a typical pattern for joining a key/value table where the (id/key) pairs are unique.
Edit Unfortunately it generates duplicate result set rows in situations where there's a duplicate key for a particular value. To deal with that, it's necessary to deduplicate the key/value table (processing) in this case.
This subquery will do that, taking the latest date value.
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
Then you have to use that subquery in the main query. This is where it would be good if MySQL had common table expressions. But it doesn't so things get kind of verbose.
SELECT o.id AS order_id, o.status,
p1.date AS date_request,
p2.date AS date_request2,
p3.date AS date_invoice
FROM orders o
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p1 ON o.id = p1.order_id AND p1.type='send_request'
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p2 ON o.id = p2.order_id AND p2.type='send_request2'
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p3 ON o.id = p3.order_id AND p3.type='send_invoice'
ORDER BY 1,2
Related
Ive got this query and I want to get all names from those clients that have the highest price of a day.
If multiple clients exist having the same max price, they shall be selected too.
I managed to get the customers with max price grouped by date but I dont think it gives me both customers if they have the same max value on the same day.
The names should be distinct.
The output needs to be as follows:
| Name (asc) |
------------------
| customer name |
| customer name |
| ...... |
The Orders table looks as follows:
|Client|Price|Orderdate |
------------------------
|1 |100.0|2010.01.10|
|... |... | ..... |
and the Client table:
|Client_NR|Name |
-----------------------
|1 |customer#001|
|2 |customer#002|
select distinct k1.NAME from Orders a LEFT JOIN Order b on a.Orderdate = b.Orderdate
JOIN Client k1 on k1.Client_NR = a.Client
where a.Price IN
(SELECT MAX(a.Price) from Order a group by Orderdate)
order by NAME asc
I presume my error lies within the Join Client line but I just cant figure it out.
Ive tried to use a.price = b.price in the first join but the test would fail.
Any advise is highly appreciated.
WITH cte AS ( SELECT Client.Name,
RANK() OVER (PARTITION BY Orders.Orderdate
ORDER BY Orders.Price DESC) rnk
FROM Client
JOIN Orders ON Client.Client_NR = Orders.Client )
SELECT Name
FROM cte
WHERE rnk = 1
ORDER BY Name
i'm looking for solution to check if multiple rows from one table have match in other table. In my situation i need to check if items from orders are in storage. Currently I use php to check orders - script is taking open orders and foreach one by one to check storage. It's generating quite a lot of queries and it's not efficient at all and i'm looking for solution to do this via sql query.
Desired result should be:
OrderId | Date | Products
1002/02 | 2020/08/16 | 1x Ipod; 2x battery; 9x some item;
0333/4 | 2020/06/22 | 10x shelf
Storage products table
id | id_product | quantity
Orders
id | reference | id_status | created_at
Order Products
Id | id_order | quantity | id_storage_product
I've written some code to generate table visible above but result it's not even close to desired.
select('orders.id', orders.created_at','orders.reference', 'storage_products.id as storageProductId')
->join('order_products', 'orders.id', '=', 'order_products.id_order')
->join('storage_products', 'order_products.id_product', '=', 'storage_products.id_product')
->where('storage_products.quantity', '>=', 'order_products.quantity')
->whereIn('orders.id_status', array(1, 2)) //get new orders/ open
->where('order_products.id_storage_product', null)
->groupBy('orders.id');
Clean sql:
SELECT `orders`.`id`,
`orders`.`created_at`,
`orders`.`reference`,
`storage_products`.`id` AS `storageProductId`,
`order_products`.`id_order`
FROM `orders`
INNER JOIN `order_products`
ON `orders`.`id` =
`order_products`.`id_order`
INNER JOIN `storage_products`
ON `order_products`.`id_product` =
`storage_products`.`id_product`
WHERE `storage_products`.`quantity` >=
'order_products.quantity'
AND `orders`.`id_status` IN ( 1, 2 )
AND `order_products`.`id_storage_product` IS NULL
GROUP BY `orders`.`id`
ORDER BY `orders`.`id` ASC
So code should find open orders (id_status); where storage quantity is equal or greater than product in order; where id_storage_products is null (means product bought on website but it was not in storage when ordered).
Upper query result is wrong because it showed me partial match to storage - even without checking quantity (some products have 0 but still displayed).
For any help many thanks
EDIT: fiddle sample: https://www.db-fiddle.com/f/6jKvKXPYvsLeXgm3Qv1nHu/0
Your query contains the condition:
AND `order_products`.`id_storage_product` IS NULL
but in your sample data all values are 0.
So instead I use COALESCE() to cover both cases.
Also I removed the condition:
AND `orders`.`id_status` IN ( 1, 2 )
because the column id_status is not included in the definition of the table orders in your sample data.
This query works:
SELECT o.id,
o.reference,
o.created_at,
GROUP_CONCAT(op.quantity, 'x', op.id_product separator ' ;') products
FROM orders o
INNER JOIN order_products op ON o.id = op.id_order
INNER JOIN storage_products sp ON op.id_product = sp.id_product
WHERE sp.quantity >= op.quantity AND COALESCE(op.id_storage_product, 0) = 0
GROUP BY o.id, o.reference, o.created_at
ORDER BY o.id ASC
See the demo.
Results:
| id | reference | created_at | products |
| --- | --------- | ------------------- | ------------- |
| 2 | 345554/02 | 2020-08-22 00:00:00 | 3x188 ; 1x155 |
If you also join the table products (I assume there is such a table) you can get the names of the products instead of their ids.
I tried the following query on the db-fiddle link and this works.
SELECT
orders.reference, orders.created_at, order_products.id_product
FROM
storage_products
LEFT JOIN
order_products ON storage_products.id_product = order_products.id_product
LEFT JOIN
orders ON orders.id = order_products.id_order;
What I did in the query is calling all storage_products with the same id_product in order_products and proceed to call all orders in the called order_products.
I'm stuck on this one. I have three tables:
Table 1:
**ORDERS**
| ORDER_NO | PRODUCT_NO | CLIENT_NO | UNITS | ORDER_DATE |
Table 2:
**CLIENTS**
| CLIENT_NO | NAME | LOCATION | SELLER_NO | OWES | OVERPAID | CREDIT_LIMIT |
Table 3:
**PRODUCTS**
| PRODUCT_NO | DESCRIPTION | UNIT_PRICE | AVAILABLE_STOCK |
Now, what I have to do is to update column OWES in table CLIENTS so it contains total amount of money of all the orders they made.
This is as far as I got:
update CLIENTS set OWES = (select sum(o.UNITS) from ORDERS o where CLIENTS.CLIENT_NO = o.CLIENT_NO);
That seems to work just fine to get a total number of orders, but than I have to multiply it by the price of given item (whichever the order was for) and I get myself confused.
I tried for example:
update CLIENTS set OWES = ( select sum(o.UNITS) from ORDERS o where CLIENTS.CLIENT_NO = o.CLIENT_NO)*(select UNIT_PRICE from PRODUCTS where PRODUCT_NO= any(select PRODUCT_NO from ORDERS));
But that returns ERROR 1242 (21000): Subquery returns more than 1 row
What am I doing wrong? Would it be better to use update CLIENTS as ( some complicated sub query goes here) ?
Can anyone help me out and be so kind to throw in some explanation why such solution and not some other? It just seem like I didn't get something on more basic level and now I'm struggling.
Thanks in advance.
I think you can just do a join in the subquery and do the appropriate aggregation:
update CLIENTS
set OWES = (select sum(o.UNITS * p.unit_price)
from ORDERS o join
products p
on o.product_no = p.product_no
where CLIENTS.CLIENT_NO = o.CLIENT_NO
);
Your syntax is a little off. The general syntax for updating from other tables is:
UPDATE table1
JOIN table2 ON table2.mycolumn = table1.mycolumn
JOIN (
SELECT foo, SUM(bar) as sumbar FROM table3) table3sum ON table3sum.foo = table1.foo
SET
table1.foo = table2.bar,
table1.baz = table3sum.sumbar
Amazon offers their marketplace customers a CSV report which contains information about every article you sold. There are four rows per article, looking like this:
+----------------------+------------+-------------------+--------+
| orderid | amounttype | amountdescription | amount |
+----------------------+------------+-------------------+--------+
| 305-2406165-0572365 | ItemPrice | Principal | 2.98 |
| 305-2406165-0572365 | ItemPrice | Shipping | 3.89 |
| 305-2406165-0572365 | ItemFees | Commission | -0.45 |
| 305-2406165-0572365 | ItemFees | ShippingHB | -0.59 |
+----------------------+------------+-------------------+--------+
As you can see, every article has four rows, two for the actual selling price and two for the fees I have to pay to Amazon.
I import this CSV file into a SQL-table using MySQL. Selecting some data including the price looks like this:
SELECT DISTINCT
report.posteddate AS Date,
orders.OrderID,
orders.ExternalOrderID AS AZNr,
report.amount AS ArtPrice
FROM
report,
orders
WHERE
orders.ExternalOrderID = report.orderid
AND report.amountdescription = 'Principal'
AND report.transactiontype = 'Order'
ORDER by Date DESC
To get just the item price without the shipping I do a selection to get only the rows where amountdescription is "Principal". The transactiontype can be ignored in order to solve my problem.
What I want to do:
I want to extract both fields of amount where amounttype is "ItemFees", add them together and display the result as a single field. After this selection, a row should look like this:
+------------+---------+---------------------+----------+-------+
| Date | OrderID | AZNr | ArtPrice | Fees |
+------------+---------+---------------------+----------+-------+
| 24.07.2014 | 267720 | 305-2406165-0572365 | 2.98 | -1.04 |
+------------+---------+---------------------+----------+-------+
I tried to run a subquery for both rows with a selection to amounttype = "ItemFees" and combine the results, but I ended up in an error saying that my subquery returns more than one row. This is the query:
SELECT DISTINCT
report.posteddate AS Date,
orders.OrderID,
orders.ExternalOrderID AS AZNr,
report.amount AS ArtPrice,
(SELECT
SUM(report.amount)
FROM
report,
orders
WHERE
orders.ExternalOrderID = report.orderid
AND report.amountdescription = 'Commission') +
(SELECT
SUM(report.amount)
FROM
report,
orders
WHERE
orders.ExternalOrderID = report.orderid
AND report.amountdescription = 'ShippingHB') AS Fees
FROM
report,
orders
WHERE
orders.ExternalOrderID = report.orderid
AND report.amountdescription = 'Principal'
AND report.transactiontype = 'Order'
ORDER by Date DESC
Does anybody have an idea how to sum up two values from two different rows with the given condition (see WHERE-clause)? Also, I need to extract the shipping value, but I think this is the same question.
Thank you in advance.
you can calculate itemprice and itemfees with two queries and join them
select a.orderid, a.price, b.fees
from (select orderid, sum(amount) price from report where amounttype='ItemPrice' group by orderid) a
join (select orderid, sum(amount) fees from report where amounttype='ItemFees' group by orderid) b
on a.orderid = b.orderid
this asumes there is at least one row with itemprice and one row with itemfees. otherwise you should use an outer join.
I have three tables actually on virturt mart table one is orders, another is item & one is order_user_info
to get the user first name i need to join order_user_info table
but when i join it shows the result info double, below i have mentioned the query & result please guide how can avoid double result
*FOR JOIN FIRST NAME I AM USING BELOW MENTIONED QUERY *
LEFT JOIN `urbanite_virtuemart_order_userinfos` as Uinfo ON Uinfo.virtuemart_order_id=i.virtuemart_order_id
*COMPLETE QUERY *
SELECT SQL_CALC_FOUND_ROWS o.created_on AS intervals, CAST( i.`created_on` AS DATE ) AS created_on, Uinfo.`first_name`, o.`order_number`, SUM(DISTINCT i.product_item_price * product_quantity) as order_subtotal_netto, SUM(DISTINCT i.product_subtotal_with_tax) as order_subtotal_brutto, COUNT(DISTINCT i.virtuemart_order_id) as count_order_id, SUM(i.product_quantity) as product_quantity FROM `urbanite_virtuemart_order_items` as i
LEFT JOIN `urbanite_virtuemart_orders` as o ON o.virtuemart_order_id=i.virtuemart_order_id
LEFT JOIN `urbanite_virtuemart_order_userinfos` as Uinfo ON Uinfo.virtuemart_order_id=i.virtuemart_order_id AND Uinfo.created_on = i.created_on AND Uinfo.virtuemart_user_id = o.virtuemart_user_id
WHERE (`i`.`order_status` = "S") AND i.virtuemart_vendor_id = "63" AND DATE( o.created_on ) BETWEEN "2013-06-01 05:00:00" AND "2013-06-30 05:00:00"
GROUP BY intervals
ORDER BY created_on DESC LIMIT 0, 400
result i am getting with out join like below
intervals | Created_on | order_no | order_subtotalnetto | order_subtotalbruto | count_order_id | product_quantity
2013-06-12 09:47:16 |2013-06-12 | 43940624 | 200.00000 | 200.00000 | 1 | 2
result i am getting with join for firstname like below
intervals | Created_on | order_no | f_name | order_subtotalnetto | order_subtotalbruto | count_order_id | product_quantity
2013-06-12 09:47:16 |2013-06-12 | Fatin Bokhari | 43940624 | 200.00000 | 200.00000 | 1 | 4
see in with out join for first name it show product_quantity = 2 but when i join it shows the value double, i tried distinct but cant go this way as it show the product quantity = 1 every time
Kindly need rescue!
oh actually the rows comes twice in a urbanite_virtuemart_order_userinfos table so i used where clause & it works
WHERE (`i`.`order_status` = "S") AND i.virtuemart_vendor_id = "63" AND DATE( o.created_on ) BETWEEN "2013-06-01 05:00:00" AND "2013-06-30 05:00:00" AND Uinfo.`address_type` = 'BT'