UNION query results in a new row instead of new column - mysql

The following query returns a result with 5 columns (
date ,lowest_hr_price ,max_hr_price ,min_price , max_price )
instead of
(date ,lowest_hr_price ,max_hr_price , min_price ,max_price , AvgPrice, AvgPieces ).
AvgPrice and AvgPieces are instead added as rows .
(select date(m.min_max_date) as date,
max(case when m.lbl='min_hr_price' then m.min_max_hr_price else null end) as lowest_hr_price,
max(case when m.lbl='max_hr_price' then m.min_max_hr_price else null end) as max_hr_price,
max(case when n.lbl='min_price' then n.min_max_price else null end) as min_price,
max(case when n.lbl='max_price' then n.min_max_price else null end) as max_price
from (select 'min_hr_price' as lbl, price as min_max_hr_price, date_time as min_max_date
from mytable
where date_time in (select min(date_time) as min_date from mytable group by date(date_time)) and symbol = 'dollar'
UNION
select 'max_hr_price', price, date_time
from mytable WHERE symbol = 'dollar'
AND date_time in (select max(date_time) as max_date from mytable WHERE symbol = 'dollar' group by date(date_time))) as m,
(
select 'min_price' as lbl,
min(date_time) as min_max_date,
min(price) as min_max_price
from mytable
WHERE symbol = 'dollar'
group by date(date_time)
UNION
select 'max_price' as lbl,
max(date_time) as min_max_date,
max(price) as min_max_price
from mytable
WHERE symbol = 'dollar'
group by date(date_time)
) n
where m.min_max_date=n.min_max_date
group by date(m.min_max_date)
order by m.min_max_date DESC
)
UNION
(SELECT null, null, date_time, avg (price) as AvgPrice, avg (pieces) as AvgPieces FROM mytable
WHERE symbol = 'dollar'
group by date(date_time))
Actual result:
date |lowest_hr_price | max_hr_price | min_price | max_price
------------------------------------------------------------------------------------
2018-03-06 | 1 | 2 | 0 | 10
NULL | NULL | {date} | {avgprice} | {avgpieces}
Expected result:
date |lowest_hr_price | max_hr_price | min_price | max_price | AvgPrice | AvgPieces
-------------------------------------------------------------------------------------------------------------
2018-03-06 | 1 | 2 | 0 | 10 | {avgprice}| {avgpieces}

if you instead of an union (select rows append one select to each others ) need all the result on the same rows
in this case you could use a cross join eg :
select distinct * from (
(select date(m.min_max_date) as date,
max(case when m.lbl='min_hr_price' then m.min_max_hr_price else null end) as lowest_hr_price,
max(case when m.lbl='max_hr_price' then m.min_max_hr_price else null end) as max_hr_price,
max(case when n.lbl='min_price' then n.min_max_price else null end) as min_price,
max(case when n.lbl='max_price' then n.min_max_price else null end) as max_price
from (select 'min_hr_price' as lbl, price as min_max_hr_price, date_time as min_max_date
from mytable
where date_time in (select min(date_time) as min_date from mytable group by date(date_time)) and symbol = 'dollar'
UNION
select 'max_hr_price', price, date_time
from mytable WHERE symbol = 'dollar'
AND date_time in (select max(date_time) as max_date from mytable WHERE symbol = 'dollar' group by date(date_time))) as m,
(
select 'min_price' as lbl,
min(date_time) as min_max_date,
min(price) as min_max_price
from mytable
WHERE symbol = 'dollar'
group by date(date_time)
UNION
select 'max_price' as lbl,
max(date_time) as min_max_date,
max(price) as min_max_price
from mytable
WHERE symbol = 'dollar'
group by date(date_time)
) n
where m.min_max_date=n.min_max_date
group by date(m.min_max_date)
order by m.min_max_date DESC
) ) T1 INNER join
(SELECT null, null, date_time, avg (price) as AvgPrice, avg (pieces) as AvgPieces FROM mytable
WHERE symbol = 'dollar'
group by date(date_time)) T2 ON date(T1.date) = date(T2.date_time)

Related

How to use alias in where clause in mysql with lead lag functions

I am trying to compare value with an alias but it says scolumn not recognized. Docs says can't use alias in where clause
WITH CTE AS
(
SELECT
StockCode AS TopProduct,
COUNT(CustomerID) AS mostCustomers
FROM
dbfinalweek.`e-commerce`
GROUP BY
StockCode
ORDER BY
mostCustomers DESC
LIMIT 1
)
SELECT
StockCode AS stock, CustomerID,
LEAD(StockCode, 1) OVER (ORDER BY CustomerID, InvoiceDate) AS NextItem,
LAG(StockCode, 1) OVER () AS PreviousItem,
InvoiceDate
FROM
dbfinalweek.`e-commerce` AS table1
WHERE
(table1.StockCode = (SELECT CTE.TopProduct FROM CTE)) OR
(table1.NextItem = (SELECT CTE.TopProduct FROM CTE))
Here is my query. Any idea how I could make Table1.NextItem work?
Windo function can't be used directly so you must make a second cte for that`
CREATE TABLE `e-commerce` (StockCode int,CustomerID int,mostCustomers int,InvoiceDate date)
with CTE AS
(
Select
StockCode as TopProduct
,count(CustomerID) as mostCustomers
from `e-commerce`
group by StockCode
order by mostCustomers desc
limit 1
),
cte2 as(
select
StockCode as stock
,CustomerID
, Lead(StockCode,1) over( order by CustomerID,InvoiceDate) as NextItem
,Lag(StockCode,1) over() as PreviousItem
,InvoiceDate
from `e-commerce` )
SELECT
* FROM cte2
WHERE (stock = (Select CTE.TopProduct from CTE)) OR (NextItem=(Select CTE.TopProduct from CTE))
stock | CustomerID | NextItem | PreviousItem | InvoiceDate
----: | ---------: | -------: | -----------: | :----------
db<>fiddle here

Count Total from Multiple Table

I have 3 tables (ticket1, ticket2, ticket3) that contain same field:
ticket1: ticket2: ticket2:
======== ======== ========
ticket_id ticket_id ticket_id
status status status
And my query just like this:
("SELECT (SELECT COUNT( * ) FROM `ticket1` WHERE `status` =9) AS done,
(SELECT COUNT( * ) FROM `ticket1` WHERE `status` =10) AS Incomplete,
(SELECT COUNT( * ) FROM `ticket1` WHERE `status` =2) AS New")
This is to count ticket and filter by status.
And my question is, how i can count all ticket into total Done, Incomplete, and New from ticket1, ticket2, ticket3.
Help me guys, thanks..
I guess the 3d table's name is ticket3, right?
SELECT
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 9) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 9) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 9) AS TotalDone,
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 10) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 10) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 10) AS TotalIncomplete,
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 2) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 2) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 2) AS TotalNew
Try this.
select status, count(1) from
(select * from ticket1
union all
select * from ticket2
union all
select * from ticket3) group by status;
Let me know if you face any issues
you could select from union all
select sum(case when status = 9 then 1 else 0 end) done,
sum(case when status = 10 then 1 else 0 end) Incomplete,
sum(case when status = 2 then 1 else 0 end) New,
sum(case when status in (9,10,2) then 1 else 0 end) deon_incomplete_new,
count(*) tot
from (
select ticket_id, status from ticket1
union all
select ticket_id, status from ticket2
union all
select ticket_id, status from ticket2
) t
I would suggest:
select sum(case when status = 9 then cnt else 0 end) as done,
sum(case when status = 10 then cnt else 0 end) as incomplete,
sum(case when status = 2 then cnt else 0 end) as new
from ((select status, count(*) as cnt from ticket1 group by status
) union all
(select status, count(*) as cnt from ticket2 group by status
) union all
(select status, count(*) as cnt from ticket3 group by status
)
) t;
Or, you might consider putting the values in separate rows using group by.
If performance is an issue and you have lots of other tickets statuses (or more specifically lots of rows with different statuses), then where status in (2, 9, 10) in each of the subqueries might help.

Offset with Quantity in SQL

Let us suppose we have following tables
product_id | quantity
1 | 250
2 | 150
3 | 120
4 | 300
5 | 301
How do we know that the item number of 401th in SQL? (the answer should be product_id : 3). The query should return the product_id
Let us assume also the row has been in order
You can use Correlated query to find cummulative sum and then filter range using between to find the required slot:
select product_id
from (
select a.*,
coalesce((
select sum(quantity)
from your_table b
where b.product_id < a.product_id
), 0) + 1 cquant1,
(
select sum(quantity)
from your_table b
where b.product_id <= a.product_id
) cquant2
from your_table a
) t
where 401 between cquant1 and cquant2;
Demo
You can also use user variable for this:
select *
from (
select product_id,
#sum1 := #sum1 + coalesce((
select quantity
from your_table x
where x.product_id < t.product_id
order by x.product_id desc limit 1
), 0) as cquantity1,
#sum2 := #sum2 + quantity as cquantity2
from your_table t,
(select #sum1 := 0, #sum2 := 0) t2
order by product_id
) t
where 401 between cquantity1 and cquantity2;
Demo
In case of ORACLE, this will not work with SQLServer
This is by using LAG and SUM OVER() functions,
SELECT PRODUCT_ID FROM
(
SELECT PRODUCT_ID
, LAG(CUM_QUAN, 1, 0) OVER (ORDER BY PRODUCT_ID) AS START_QUAN
, CUM_QUAN END_QUAN
FROM
(
SELECT PRODUCT_ID
, QUANTITY
, SUM(QUANTITY) OVER (ORDER BY PRODUCT_ID) AS CUM_QUAN
FROM YOUR_TABLE
)
) WHERE 401 BETWEEN START_QUAN AND END_QUAN
You can do this with variables by getting a cumulative sum. However, Gurv's answer is way too complicated.
I think this is the simplest way:
select t.*
from (select t.*, (#s := #s + quantity) as running_quantity
from t cross join
(select #s := 0) params
order by product_id
) t
where 401 < running_quantity and
401 >= running_quantity - quantity;

Getting Row Count by SubQuery which has GROUP BY - MySQL

I currently have a table with following schema:
CREATE TABLE `order_handling` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`oh_no` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL,
`date_request` datetime DEFAULT NULL,
`status` smallint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I want to perform query that will result like this:
+-------------------------------------------------------------+
| MonthDone | OhProgress | OhHold | OhCancel | OhDone | Total |
+-------------------------------------------------------------+
| June 2016 | 2 | 1 | 1 | 3 | 7 |
| July 2016 | 6 | 1 | null | null | 7 |
+-------------------------------------------------------------+
My Query is,
SELECT
DATE_FORMAT(`oh`.`date_request`, '%m-%Y') AS `IdMonth`,
(SELECT COUNT(*) FROM order_handling as oh1 WHERE `oh1`.`status` IN (1,2) GROUP BY IdMonth) As OhProgress,
(SELECT COUNT(*) FROM order_handling as oh2 WHERE `oh2`.`status` IN (3) GROUP BY IdMonth) As OhHold,
(SELECT COUNT(*) FROM order_handling as oh3 WHERE `oh3`.`status` IN (4) GROUP BY IdMonth) As OhCancel,
(SELECT COUNT(*) FROM order_handling as oh3 WHERE `oh3`.`status` IN (5) GROUP BY IdMonth) As OhDone,
(SELECT COUNT(*) FROM order_handling as oh5 WHERE `oh5`.`status` IN (1,2,3,4,5) GROUP BY IdMonth) As SumTotal
FROM `order_handling` `oh`
GROUP BY DATE_FORMAT(`oh`.`date_request`, '%M %Y')
ORDER BY `oh`.`date_request` ASC
The output was not expected. If I change SubQuery GROUP BY with DATE_FORMAT(date_request, '%m-%Y') like follows:
SELECT
DATE_FORMAT(`oh`.`date_request`, '%m-%Y') AS `IdMonth`,
(SELECT COUNT(*) FROM order_handling as oh1 WHERE `oh1`.`status` IN (1,2) GROUP BY DATE_FORMAT(`oh1`.`date_request`, '%m-%Y')) As OhProgress,
(SELECT COUNT(*) FROM order_handling as oh2 WHERE `oh2`.`status` IN (3) GROUP BY DATE_FORMAT(`oh2`.`date_request`, '%m-%Y')) As OhHold,
(SELECT COUNT(*) FROM order_handling as oh3 WHERE `oh3`.`status` IN (4) GROUP BY DATE_FORMAT(`oh3`.`date_request`, '%m-%Y')) As OhCancel,
(SELECT COUNT(*) FROM order_handling as oh4 WHERE `oh4`.`status` IN (5) GROUP BY DATE_FORMAT(`oh4`.`date_request`, '%m-%Y')) As OhDone,
(SELECT COUNT(*) FROM order_handling as oh5 WHERE `oh5`.`status` IN (1,2,3,4,5) GROUP BY DATE_FORMAT(`oh5`.`date_request`, '%m-%Y')) As SumTotal
FROM `order_handling` `oh`
GROUP BY DATE_FORMAT(`oh`.`date_request`, '%M %Y')
ORDER BY `oh`.`date_request` ASC
It gives me Error: Subquery return more than 1 row
Here is my SQLFiddle
Please help,
thank you
No need for subqueries
SELECT
DATE_FORMAT(`date_request`, '%m-%Y') AS `IdMonth`,
SUM(status IN (1,2) ) As OhProgress,
SUM(status IN (3) ) As OhHold,
SUM(status IN (4) ) As OhCancel,
SUM(status IN (5) ) As OhDone,
SUM(status IN (1,2,3,4,5)) As SumTotal
FROM `order_handling`
GROUP BY DATE_FORMAT(`date_request`, '%M %Y')
ORDER BY `date_request` ASC
SQLFiddle (courtesy of #Giorgos)
Try this:
SELECT
DATE_FORMAT(oh.`date_request`, '%m-%Y') AS `IdMonth`,
(SELECT COUNT(*)
FROM order_handling as oh1
WHERE oh1.`status` IN (1,2) AND
`IdMonth` = DATE_FORMAT(oh1.`date_request`, '%m-%Y')) As OhProgress,
(SELECT COUNT(*)
FROM order_handling as oh2
WHERE oh2.`status` IN (3) AND
`IdMonth` = DATE_FORMAT(oh2.`date_request`, '%m-%Y')) As OhHold,
(SELECT COUNT(*)
FROM order_handling as oh3
WHERE oh3.`status` IN (4) AND
`IdMonth` = DATE_FORMAT(oh3.`date_request`, '%m-%Y')) As OhCancel,
(SELECT COUNT(*)
FROM order_handling as oh4
WHERE oh4.`status` IN (5) AND
`IdMonth` = DATE_FORMAT(oh4.`date_request`, '%m-%Y')) As OhDone,
(SELECT COUNT(*)
FROM order_handling as oh5
WHERE oh5.`status` IN (1,2,3,4,5) AND
`IdMonth` = DATE_FORMAT(oh5.`date_request`, '%m-%Y')) As SumTotal
FROM `order_handling` oh
GROUP BY DATE_FORMAT(oh.`date_request`, '%M %Y')
ORDER BY oh.`date_request` ASC
Demo here

Union Select Column Mismatch

Here's my query:
SELECT
FROM_UNIXTIME( date_added, '%m-%d-%Y' ) AS formatted_date,
SUM( tb =1 ) AS sum_users,
SUM( tb =2 ) AS sum_links,
SUM( tb =3 ) AS sum_ads,
SUM( tb =4 ) AS sum_actions
FROM (
SELECT date_added, 1 AS tb
FROM users_list WHERE 1=1
UNION ALL
SELECT date_added, 2
FROM users_links WHERE 1=1
UNION ALL
SELECT date_served, 3
FROM ads_served WHERE 1=1
UNION ALL
SELECT date_served, 4
FROM actions WHERE 1=1
) AS t
GROUP BY formatted_date
ORDER BY formatted_date DESC
Here's my table data:
users_list
id date_added
1 1234567890
2 1334567890
3 1434567890
users_links
id date_added
1 1244567890
2 1354567890
3 1464567890
ads_served
id date_served revenue
1 1234567891 0.01
2 1334567892 0.02
3 1434567893 0.02
actions
id date_served
1 1234561890
2 1334562890
3 1434563890
I am trying to sum the revenue for formatted_date in the ads_served table as a 6th column for the output query. I am lost as to where to start. If I add the sum(revenue) to the union select I get a "column mismatch" error.
Column revenue belongs to ads_served but you are selecting from a sub query where revenue is not present. Add it to the subquery:
SELECT
FROM_UNIXTIME( date_added, '%m-%d-%Y' ) AS formatted_date,
SUM( tb =1 ) AS sum_users,
SUM( tb =2 ) AS sum_links,
SUM( tb =3 ) AS sum_ads,
SUM( tb =4 ) AS sum_actions,
SUM( revenue ) As sum_revenue
FROM (
SELECT date_added, 1 AS tb, 0 As revenue
FROM users_list WHERE 1=1
UNION ALL
SELECT date_added, 2, 0
FROM users_links WHERE 1=1
UNION ALL
SELECT date_served, 3, revenue
FROM ads_served WHERE 1=1
UNION ALL
SELECT date_served, 4, 0
FROM actions WHERE 1=1
) AS t
GROUP BY formatted_date
ORDER BY formatted_date DESC
Try in this way. Why do you use 1=1 ?
SELECT
FROM_UNIXTIME( date_added, '%m-%d-%Y' ) AS formatted_date,
SUM( tb =1 ) AS sum_users,
SUM( tb =2 ) AS sum_links,
SUM( tb =3 ) AS sum_ads,
SUM( tb =4 ) AS sum_actions,
sum(total) as tot_rev
FROM (
SELECT date_added,'' as total, 1 AS tb
FROM users_list WHERE 1=1
UNION ALL
SELECT date_added,'', 2
FROM users_links WHERE 1=1
UNION ALL
SELECT date_served,revenue, 3
FROM ads_served WHERE 1=1
UNION ALL
SELECT date_served,'', 4
FROM actions WHERE 1=1
) AS t
GROUP BY formatted_date
ORDER BY formatted_date DESC