UNION ALL query missing data? - mysql

Using UNION ALL to get results from two queries but it is losing a row of data. If I switch which select statement comes first the missing data switches to a different row. I know each slect statement pulls correct information when ran seperate but when put together not working correctly. The following is my query:
SELECT YEAR( orderDate ) AS "SalesYear"
, MONTH( orderDate ) AS "SalesMonth"
, SUM( orderTotal ) AS "TotalSales"
, orderDetails.productID
FROM orders
INNER JOIN orderdetails
ON orders.orderID = orderDetails.orderID
INNER JOIN products
ON orderDetails.productID = products.productID
UNION ALL
SELECT YEAR( orderDate ) AS "SalesYear"
, MONTH( orderDate ) AS "SalesMonth"
, SUM( orderTotal ) AS "TotalSales"
, instorepurchasedetails.productID
FROM in_storepurchase
INNER JOIN instorepurchasedetails
ON in_storepurchase.isPurchaseID = instorepurchasedetails.isPurchaseID
INNER JOIN products
ON instorepurchasedetails.productID = products.productID
GROUP BY YEAR(orderDate ), MONTH( orderDate ), orderTotal, productID
Any ideas why this is happening and what I can do?

Your need to add a GROUP BY clause to each SELECT block, and specify the correct columns, something like this:
SELECT "SalesYear"
, "SalesMonth"
, SUM( "TotalSales" ) AS "TotalSales"
, productID
FROM (
SELECT YEAR( orderDate ) AS "SalesYear"
, MONTH( orderDate ) AS "SalesMonth"
, SUM( orderTotal ) AS "TotalSales"
, orderDetails.productID
FROM orders
INNER JOIN orderdetails
ON orders.orderID = orderDetails.orderID
INNER JOIN products
ON orderDetails.productID = products.productID
GROUP BY YEAR(orderDate ), MONTH( orderDate ), orderDetails.productID
UNION ALL
SELECT YEAR( orderDate ) AS "SalesYear"
, MONTH( orderDate ) AS "SalesMonth"
, SUM( orderTotal ) AS "TotalSales"
, instorepurchasedetails.productID
FROM in_storepurchase
INNER JOIN instorepurchasedetails
ON in_storepurchase.isPurchaseID = instorepurchasedetails.isPurchaseID
INNER JOIN products
ON instorepurchasedetails.productID = products.productID
GROUP BY YEAR(orderDate), MONTH(orderDate), instorepurchasedetails.productID
) x
GROUP BY "SalesYear", "SalesMonth", productID
I also removed the orderTotal from the GROUP BY clause because I don't think that's what you needed.
EDIT: Updated based on OP comment.

SELECT `x`.`SalesYear`,
`x`.`SalesMonth`,
SUM( `x`. `TotalSales`) AS "TotalSales",
productID
FROM
(
SELECT YEAR( orderDate ) AS "SalesYear",
MONTH( orderDate ) AS "SalesMonth",
SUM( orderTotal ) AS "TotalSales",
orderDetails.productID
FROM orders
INNER JOIN orderdetails ON orders.orderID = orderDetails.orderID
INNER JOIN products ON orderDetails.productID = products.productID
GROUP BY YEAR(orderDate ) , MONTH( orderDate ), productID
UNION ALL
SELECT YEAR( orderDate ) AS "SalesYear",
MONTH( orderDate ) AS "SalesMonth",
SUM( orderTotal ) AS "TotalSales",
instorepurchasedetails.productID
FROM in_storepurchase
INNER JOIN instorepurchasedetails ON in_storepurchase.isPurchaseID = instorepurchasedetails.isPurchaseID
INNER JOIN products ON instorepurchasedetails.productID = products.productID
GROUP BY YEAR(orderDate ) , MONTH( orderDate ), productID
) x
GROUP BY `x`.`SalesMonth`, productID
ORDER BY `x`.`SalesMonth` ASC

Related

this query shows #1248 - Every derived table must have its own alias

SELECT X.workorder_id,X.order_id FROM mr_workorder_data AS X
LEFT JOIN
(SELECT order_id, workorder_id, GROUP_CONCAT(trim_id SEPARATOR '|') AS trim_id_arr
FROM mr_workorder_data
WHERE order_id = X.order_id AND workorder_id =
X.workorder_id GROUP BY order_id)
WHERE X.data_type = 'Accessories' GROUP BY X.workorder_id
You have a left join ( subselect ) without an alias add (eg:) T at the end of the subquery ()
SELECT X.workorder_id,X.order_id
FROM mr_workorder_data AS X
LEFT JOIN ( SELECT order_id,workorder_id,
GROUP_CONCAT(trim_id SEPARATOR '|') AS trim_id_arr
FROM mr_workorder_data
WHERE order_id = X.order_id AND workorder_id = X.workorder_id
GROUP BY order_id ) T
WHERE X.data_type = 'Accessories'
GROUP BY X.workorder_id

Order by on datetime field is not working - mysql

I want to get the date of last order placed and mobile# for all the customers.
This is my query.
SELECT c.customer_id, c.mobile, COALESCE( MAX( o.order_datetime ) , '0000-00-00 00:00:00' ) AS last_order_date
FROM table_orders AS o
RIGHT JOIN table_customers AS c ON o.customer_id = c.customer_id
GROUP BY c.customer_id
ORDER BY DATE( o.order_datetime )
It works fine. But not giving me data in asc order of o.order_datetime?
What is the error in query?
Try this
ORDER BY DATE( o.order_datetime ) DESC

How to select customer's final balance for all customer in mysql

I have 3 tables.
table_customers - customer_id, name
table_orders - order_id, customer_id, order_datetime
table_wallet - customer_id, amount, type // type 1- credit, type 2- debit
I need to get all customers, their total balance, and their last order date and order id. This is my query.
SELECT
C.customer_id,
C.name,
COALESCE( SUM(CASE WHEN type = 2 THEN -W.amount ELSE W.amount END), 0) AS value,
COALESCE( max( O.order_id ) , '0' ) AS last_order_id,
COALESCE( max( date( O.order_datetime ) ) , '0000-00-00' ) AS last_order_date
FROM
table_customers as C
LEFT JOIN
table_wallet as W
ON C.customer_id = W.customer_id
LEFT JOIN
table_orders AS O
ON W.customer_id = O.customer_id
group by C.customer_id
ORDER BY C.customer_id
Everything is coming correct except customer's total value. From result it seems its getting added multiple times.
What is wrong in query? Can anyone help me on this?
This is doing a many-to-many join on table_customers to table_orders, which will mess with your sums. Rather do this:
SELECT C.customer_id
, C.name
, IFNULL((SELECT SUM(IF(W.type=2, -1*W.amount, W.amount))
FROM table_wallet W
WHERE C.customer_id = W.customer_id),0) AS value
, IFNULL((SELECT MAX(DATE(O.order_id))
FROM table_orders O
WHERE C.customer_id = O.customer_id),'0') AS last_order_id
, IFNULL((SELECT MAX(DATE(O.order_datetime))
FROM table_orders O
WHERE C.customer_id = O.customer_id),'0000-00-00') AS last_order_date
FROM table_customers as C
ORDER BY C.customer_id
This will return one row per customer, then subquery the fields you want. I've substituted IFNULL for COALESCE as I find it cleaner, but this is a preference thing.

SQL Server : max date from two tables

I need to find the last time a customer ordered an item for all customers and all items. I figured I would start with the last time the customer ordered anything. This would involve two tables oeordhdr_sql and oehdrhst_sql both have cus_no and ord_dt.
I am getting an error on the on
select
arcusfil.cus_no, Order_Date.orddt
from
arcusfil_sql arcusfil
join
(SELECT
cus_no, MAX(MaxDate) AS orddt
FROM
(SELECT
cus_no, MAX(ord_dt) AS MaxDate
FROM
oeordhdr_sql
GROUP BY
cus_no
UNION
SELECT
cus_no, MAX(ord_dt) AS MaxDate
FROM
oehdrhst_sql
GROUP BY
cus_no) Order_date ON arcusfil.cus_no = Order_date.cus_no
You're missing a closing ) before the ON to close the inner table that you're using for the JOIN
select
arcusfil.cus_no, Order_Date.orddt
from
arcusfil_sql arcusfil
join
(SELECT
cus_no, MAX(MaxDate) AS orddt
FROM
(SELECT
cus_no, MAX(ord_dt) AS MaxDate
FROM
oeordhdr_sql
GROUP BY
cus_no
UNION
SELECT
cus_no, MAX(ord_dt) AS MaxDate
FROM
oehdrhst_sql
GROUP BY
cus_no) MaxDates
) Order_date ON arcusfil.cus_no = Order_date.cus_no
I like to use CTE's for queries such as this to keep things cleaner:
;WITH MaxDates AS (
SELECT cus_no, MAX(ord_dt) AS MaxDate
FROM oeordhdr_sql
GROUP BY cus_no
UNION
SELECT cus_no, MAX(ord_dt) AS MaxDate
FROM oehdrhst_sql
GROUP BY cus_no
),
Order_Date AS (
SELECT cus_no, MAX(MaxDate) AS orddt
FROM MaxDates
GROUP BY cus_no
)
SELECT arcusfil.cus_no, Order_Date.orddt
FROM arcusfil_sql arcusfil
INNER JOIN Order_Date on arcusfil.cus_no = Order_date.cus_no

Mysql how to put a limit on a table with join

I want to LIMIT timber orders query to 10 for pagination. The problem i'm having is the LEFT JOIN timber_order_products is counted with the LIMIT. The LIMIT should only apply to timber_orders.
$data = $DB2->query("
SELECT o.order_id
, o.order_status
, o.customer_method
, o.payment_method
, o.customer_notes
, o.order_date
, p.name product_name
, p.price product_price
FROM timber_orders o
LEFT
JOIN timber_order_products p
ON p.order_id = o.order_id
ORDER
BY order_id DESC
LIMIT 10
");
How do i LIMIT results only from a specific table? The LIMIT 10 should only apply to timber_orders. I can't group by because i need the timber_order_products rows.
You can use a subquery:
SELECT o.order_id , o.order_status, o.customer_method, o.payment_method,
o.customer_notes, o.order_date,
p.name as product_name, p.price as product_price
FROM (select o.*
from timber_orders o
order by order_id desc
limit 10
) o LEFT JOIN
timber_order_products p
on p.order_id = o.order_id
ORDER BY o.order_id DESC
LIMIT 10
Avoiding using a sub query, I would use GROUP_CONCAT. Then the products name and price can be split off in the code that displays the data:-
SELECT o.order_id
, o.order_status
, o.customer_method
, o.payment_method
, o.customer_notes
, o.order_date
, GROUP_CONCAT(CONCAT_WS('~', p.name, p.price)) AS product_name_price
FROM timber_orders o
LEFT OUTER JOIN timber_order_products p
ON p.order_id = o.order_id
GROUP BY o.order_id
, o.order_status
, o.customer_method
, o.payment_method
, o.customer_notes
, o.order_date
ORDER BY order_id DESC
LIMIT 10