Convert crosstab query into a view - mysql

I have the following query which I want to convert to a view:
SELECT
PartNum,
SUM(IF(DAYOFWEEK(DeliveryDate) = '2', value, NULL)) AS 'Mon',
SUM(IF(DAYOFWEEK(DeliveryDate) = '3', value, NULL)) AS 'Tue',
SUM(IF(DAYOFWEEK(DeliveryDate) = '4', value, NULL)) AS 'Wed',
SUM(IF(DAYOFWEEK(DeliveryDate) = '5', value, NULL)) AS 'Thu',
SUM(IF(DAYOFWEEK(DeliveryDate) = '6', value, NULL)) AS 'Fri',
SUM(IF(DAYOFWEEK(DeliveryDate) = '7', value, NULL)) AS 'Sat',
SUM(IF(DAYOFWEEK(DeliveryDate) = '1', value, NULL)) AS 'Sun',
SUM(IF(DeliveryDate > DATE_ADD(CURDATE(),INTERVAL 7 DAY), value, NULL)) AS 'Future'
FROM (
SELECT PartNum, DeliveryDate , SUM(Ordered) value FROM v_archived_items_due
GROUP BY PartNum, DeliveryDate
) t
GROUP BY PartNum;
When I try to save it as a view, I get the following error:
1349 - Views SELECT contains a subquery in the FROM clause.
The query works fine by itself. How do I turn it into a view?

MySQL does not allow subqueries in view so, without seeing any sample data to see how to rework this without the subqyery. Since this is working as expected, I would create a view of your subquery:
create view view1 as
SELECT PartNum, DeliveryDate , SUM(Ordered) value
FROM v_archived_items_due
GROUP BY PartNum, DeliveryDate;
Then just call this view in your query:
SELECT
PartNum,
SUM(IF(DAYOFWEEK(DeliveryDate) = '2', value, NULL)) AS 'Mon',
SUM(IF(DAYOFWEEK(DeliveryDate) = '3', value, NULL)) AS 'Tue',
SUM(IF(DAYOFWEEK(DeliveryDate) = '4', value, NULL)) AS 'Wed',
SUM(IF(DAYOFWEEK(DeliveryDate) = '5', value, NULL)) AS 'Thu',
SUM(IF(DAYOFWEEK(DeliveryDate) = '6', value, NULL)) AS 'Fri',
SUM(IF(DAYOFWEEK(DeliveryDate) = '7', value, NULL)) AS 'Sat',
SUM(IF(DAYOFWEEK(DeliveryDate) = '1', value, NULL)) AS 'Sun',
SUM(IF(DeliveryDate > DATE_ADD(CURDATE(),INTERVAL 7 DAY), value, NULL)) AS 'Future'
FROM view1
GROUP BY PartNum;

Behavoiur as designed
http://dev.mysql.com/doc/refman/5.1/en/create-view.html
You have to build a view from your subquery and use this.

Related

SQL query to get number of clients with last statement equal connected

I need to make a SQL query
table 'records' structure:
contact_id(integer),
client_id(integer),
worker_id(integer),
statement_status(varchar),
contact_ts(timestamp)
It has to show the following:
current date
number of clients which last statement_status was 'interested'
number of clients which last statement_status was 'not_interested' and previus status was 'not_present'
Could somebody help?
sample data:
contact_id client_id contact_ts worker_id statement_status
'1', '181', '2017-09-24 03:38:31.000000', '107', 'voicemail'
'2', '72', '2017-09-23 09:32:38.000000', '10', 'not_interested'
'3', '277', '2017-09-22 07:06:16.000000', '119', 'interested'
'4', '36', '2017-09-21 04:39:57.000000', '118', 'not_present'
'5', '33', '2017-09-20 04:12:12.000000', '161', 'voicemail'
'6', '244', '2017-09-19 02:26:30.000000', '13', 'not_interested'
'7', '346', '2017-09-18 02:30:35.000000', '255', 'interested'
'8', '128', '2017-09-17 06:20:13.000000', '52', 'not_present'
'9', '33', '2017-09-16 08:58:02.000000', '188', 'not_present'
'10', '352', '2017-09-15 08:18:40.000000', '324', 'not_interested'
'11', '334', '2017-09-14 04:27:40.000000', '373', 'interested'
'12', '2', '2017-09-13 08:44:40.000000', '40', 'not_present'
'13', '33', '2017-09-12 03:46:16.000000', '252', 'voicemail'
'14', '366', '2017-09-11 04:31:22.000000', '78', 'not_interested'
'15', '184', '2017-09-10 06:08:01.000000', '289', 'interested'
'16', '184', '2017-09-09 05:45:56.000000', '124', 'not_present'
'17', '102', '2017-09-08 07:09:30.000000', '215', 'voicemail'
'18', '140', '2017-09-07 08:09:18.000000', '196', 'not_interested'
'19', '315', '2017-09-06 05:13:40.000000', '242', 'interested'
'20', '268', '2017-09-05 07:41:40.000000', '351', 'not_present'
'21', '89', '2017-09-04 05:32:05.000000', '232', 'voicemail'
desired output:
Time, interested, not-interested
2017-09-10 06:08:01, 5, 5
I tried something with sub queries, but it obviously doesn't work:
SELECT
GETDATE()
,(select count(*)
from record a
where (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
,(select count(*)
from record a
where (select (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 2) order by a.contact_ts desc limit 1) == "interested"
and
(select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
from record b;
How should I use the inner selects?
I must write a poem, because most of my post is a code.
So maybe something from "Dead man"?
“Don't let the sun burn a hole in your ass, William Blake. Rise now, and drive your cart and plough over the bones of the dead!”
;)
Try something like this:
WITH status AS (
SELECT DISTINCT client_id,
first_value(statement_status) OVER w1 AS last_status,
nth_value(statement_status, 2) OVER w1 AS prev_status
FROM records
WINDOW w1 AS (PARTITION BY client_id ORDER BY contact_ts DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
)
SELECT CURRENT_DATE(),
SUM(last_status = 'interested') AS interesed,
SUM(last_status = 'not_interested' AND prev_status = 'not_present') AS not_interested
FROM status

SQL Get most frequent value from a column based on a condition

This query
SELECT
PlayerID, HeroTypeID, HeroTypeIDCount, Wins / (Losses + Wins) AS WinRate, Wins, Losses
FROM (
SELECT E.PlayerID AS PlayerID,
FK_HeroTypeID AS HeroTypeID,
COUNT(FK_HeroTypeID) AS HeroTypeIDCount,
SUM(CASE WHEN D.Result = 'LOSS' THEN 1 ELSE 0 END) AS Losses,
SUM(CASE WHEN D.Result = 'WIN' THEN 1 ELSE 0 END) AS Wins
FROM GamePlayerDetail D
JOIN Player E
ON D.FK_PlayerID = E.PlayerID
JOIN Game I
ON D.FK_GameID = I.GameID
WHERE PlayedDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE()
GROUP BY E.PlayerID, FK_HeroTypeID
) AS T
ORDER BY PlayerID
produces the following result:
# PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
'1', '11', '1', '1.0000', '1', '0'
'1', '13', '3', '0.3333', '1', '2'
'1', '24', '5', '0.8000', '4', '1'
'1', '27', '1', '1.0000', '1', '0'
'2', '28', '1', '0.0000', '0', '1'
'2', '6', '1', '0.0000', '0', '1'
'2', '30', '1', '0.0000', '0', '1'
'2', '7', '1', '1.0000', '1', '0'
What I'd like to do is get the most frequent FK_HeroTypeID (which is also highest value of HeroTypeIDCount) per PlayerID, but in case of ties, the highest winrate should take precedence. Here's an example of what I'd like to get:
PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
1, 24, 5, 0.8000, 4, 1
2, 7, 1, 1.0000, 1, 0
How should you write a query like this?
Edit:
Ok, here's a simple Create/Insert table for the produced result.
http://sqlfiddle.com/#!9/d644a
SELECT playerid
, herotypeid
, herotypeidcount
, winrate
, wins
, losses
FROM
( SELECT *
, CASE WHEN #prev=playerid THEN #i:=#i+1 ELSE #i:=1 END rank
, #prev:=playerid prev
FROM table1
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
WHERE rank = 1;
Here's a 'hack' solution. It works, but really shouldn't be relied upon...
SELECT *
FROM
( SELECT *
FROM table1
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
GROUP
BY playerid

"Complex" MySql request, getting some columns associated with MIN and MAX values in the same request

For example I have a dataset as below:
id, idPro, mesure2, mesure3, date
'6067', '1', '9.0', '29.3', '2013-11-17 12:48:39'
'6061', '1', '7.3', '30.3', '2013-11-17 15:20:12'
'6068', '2', '7.0', '29.3', '2013-11-17 12:48:39'
'6062', '2', '9.0', '25.3', '2013-11-17 15:20:12'
'6069', '3', '7.6', '29.0', '2013-11-17 12:48:39'
'6063', '3', '7.5', '27.0', '2013-11-17 15:20:12'
'6070', '4', '8.9', '29.1', '2013-11-17 12:48:39'
'6064', '4', '9.1', '23.1', '2013-11-17 15:20:12'
'6071', '5', '9.4', '28.9', '2013-11-17 12:48:39'
'6065', '5', '5.4', '30.9', '2013-11-17 15:20:12'
'6072', '6', '9.3', '28.9', '2013-11-17 12:48:39'
'6066', '6', '9.1', '24.9', '2013-11-17 15:20:12'
I want to output a table that have the minimal and maximal value of "mesure2" and "mesure3" grouped by idPro+Date and the time where those minimal and maximal value appeared.
So it should output something like:
idPro, mesureMin, dateMinMesure, mesureMax, timeMaxMesure, mesureType, date
'1', '7.3', '2013-11-17 12:48:39', '9.0', '2013-11-17 12:48:39', 'mesure2', '2013-11-17'
'1', '29.3', '2013-11-17 12:48:39', '30.3', '2013-11-17 15:20:12', 'mesure3', '2013-11-17'
'2', '7.0', '2013-11-17 12:48:39', '9.0', '2013-11-17 15:20:12', 'mesure2', '2013-11-17'
'2', '29.3', '2013-11-17 12:48:39', '25.3', '2013-11-17 15:20:12', 'mesure3', '2013-11-17'
...
Actually, I make a request that output the minimal and maximal value of each day for each mesure type (mesure2 or mesure3) and then I do other requests to get the date of each mesure. (I use php, and I build the request with
WHERE mesure2 = $valueReturnedByTheFirstRequest AND date LIKE '%2013-11-17%'
)
But this is a lot of sql requests, I'm looking for a way to output something similar in 1 query.
Thanks in advance
Try this query:
SELECT date,
idpro,
mesureType,
mesureMin,
( SELECT min(t.date) FROM table1 t
WHERE mesure2 = mesureMin
AND t.idpro = x1.idpro
AND x1.date = date( t.date )
) dateMinMesure ,
mesureMax,
( SELECT min(t.date) FROM table1 t
WHERE mesure2 = mesureMax
AND t.idpro = x1.idpro
AND x1.date = date( t.date )
) dateMaxMesure
FROM(
SELECT date(date) `date`,
idpro,
'measure2' mesureType,
min( mesure2 ) mesureMin,
max( mesure2 ) mesureMax
FROM table1
GROUP BY date(date), idpro, mesureType
) x1
UNION ALL
SELECT date,
idpro,
mesureType,
mesureMin,
( SELECT min(t.date) FROM table1 t
WHERE mesure3 = mesureMin
AND t.idpro = x1.idpro
AND x1.date = date( t.date )
) dateMinMesure ,
mesureMax,
( SELECT min(t.date) FROM table1 t
WHERE mesure3 = mesureMax
AND t.idpro = x1.idpro
AND x1.date = date( t.date )
) dateMaxMesure
FROM(
SELECT date(date) date,
idpro,
'measure3' mesureType,
min( mesure3 ) mesureMin,
max( mesure3 ) mesureMax
FROM table1
GROUP BY date(date), idpro, mesureType
) x1
ORDER BY date, idpro, mesuretype
demo --> http://www.sqlfiddle.com/#!2/daa51/14

MySQL count(*) everyday in a month returns [BLOB-2B] instead of number

I'm going to count every rows each day in a month with a specific user id(vwr_tid). Everything works fine - the result shows up in a table but one thing. A count each days doesn't comes up. It becomes [BLOB-xx] instead of number of rows that day. Here is my code :
SELECT MONTH_v, YEAR_V,
GROUP_CONCAT(IF(day_v=1, views, null)) AS '1',
GROUP_CONCAT(IF(day_v=2, views, null)) AS '2',
GROUP_CONCAT(IF(day_v=3, views, null)) AS '3',
GROUP_CONCAT(IF(day_v=4, views, null)) AS '4',
GROUP_CONCAT(IF(day_v=5, views, null)) AS '5',
GROUP_CONCAT(IF(day_v=6, views, null)) AS '6',
GROUP_CONCAT(IF(day_v=7, views, null)) AS '7',
GROUP_CONCAT(IF(day_v=8, views, null)) AS '8',
GROUP_CONCAT(IF(day_v=9, views, null)) AS '9',
GROUP_CONCAT(IF(day_v=10, views, null)) AS '10',
GROUP_CONCAT(IF(day_v=11, views, null)) AS '11',
GROUP_CONCAT(IF(day_v=12, views, null)) AS '12',
GROUP_CONCAT(IF(day_v=13, views, null)) AS '13',
GROUP_CONCAT(IF(day_v=14, views, null)) AS '14',
GROUP_CONCAT(IF(day_v=15, views, null)) AS '15',
GROUP_CONCAT(IF(day_v=16, views, null)) AS '16',
GROUP_CONCAT(IF(day_v=17, views, null)) AS '17',
GROUP_CONCAT(IF(day_v=18, views, null)) AS '18',
GROUP_CONCAT(IF(day_v=19, views, null)) AS '19',
GROUP_CONCAT(IF(day_v=20, views, null)) AS '20',
GROUP_CONCAT(IF(day_v=21, views, null)) AS '21',
GROUP_CONCAT(IF(day_v=22, views, null)) AS '22',
GROUP_CONCAT(IF(day_v=23, views, null)) AS '23',
GROUP_CONCAT(IF(day_v=24, views, null)) AS '24',
GROUP_CONCAT(IF(day_v=25, views, null)) AS '25',
GROUP_CONCAT(IF(day_v=26, views, null)) AS '26',
GROUP_CONCAT(IF(day_v=27, views, null)) AS '27',
GROUP_CONCAT(IF(day_v=28, views, null)) AS '28',
GROUP_CONCAT(IF(day_v=29, views, null)) AS '29',
GROUP_CONCAT(IF(day_v=30, views, null)) AS '30',
GROUP_CONCAT(IF(day_v=31, views, null)) AS '31'
FROM
(
SELECT DAY(vwr_date) AS day_v,
MONTH(vwr_date) AS MONTH_v,
Year(vwr_date) AS YEAR_V,
date(vwr_date) AS date_v,
count(vwr_id) AS views
FROM car_viewer
WHERE Year(vwr_date)='2012' AND vwr_tid='18'
GROUP BY date_v
) as viewz
GROUP BY MONTH_v, YEAR_V
ORDER BY MONTH_v, YEAR_V DESC
The script is updated from #rs : Count record each day of a month from mysql into html table
The result.
I don't see the need for GROUP_CONCAT(), when SUM() will serve your needs:
SELECT MONTH_v, YEAR_V,
SUM(IF(day_v=1, views, 0)) AS '1',
SUM(IF(day_v=2, views, 0)) AS '2',
SUM(IF(day_v=3, views, 0)) AS '3',
SUM(IF(day_v=4, views, 0)) AS '4',
SUM(IF(day_v=5, views, 0)) AS '5',
SUM(IF(day_v=6, views, 0)) AS '6',
SUM(IF(day_v=7, views, 0)) AS '7',
SUM(IF(day_v=8, views, 0)) AS '8',
SUM(IF(day_v=9, views, 0)) AS '9',
SUM(IF(day_v=10, views, 0)) AS '10',
SUM(IF(day_v=11, views, 0)) AS '11',
SUM(IF(day_v=12, views, 0)) AS '12',
SUM(IF(day_v=13, views, 0)) AS '13',
SUM(IF(day_v=14, views, 0)) AS '14',
SUM(IF(day_v=15, views, 0)) AS '15',
SUM(IF(day_v=16, views, 0)) AS '16',
SUM(IF(day_v=17, views, 0)) AS '17',
SUM(IF(day_v=18, views, 0)) AS '18',
SUM(IF(day_v=19, views, 0)) AS '19',
SUM(IF(day_v=20, views, 0)) AS '20',
SUM(IF(day_v=21, views, 0)) AS '21',
SUM(IF(day_v=22, views, 0)) AS '22',
SUM(IF(day_v=23, views, 0)) AS '23',
SUM(IF(day_v=24, views, 0)) AS '24',
SUM(IF(day_v=25, views, 0)) AS '25',
SUM(IF(day_v=26, views, 0)) AS '26',
SUM(IF(day_v=27, views, 0)) AS '27',
SUM(IF(day_v=28, views, 0)) AS '28',
SUM(IF(day_v=29, views, 0)) AS '29',
SUM(IF(day_v=30, views, 0)) AS '30',
SUM(IF(day_v=31, views, 0)) AS '31'
FROM
(
SELECT DAY(vwr_date) AS day_v,
MONTH(vwr_date) AS MONTH_v,
Year(vwr_date) AS YEAR_V,
date(vwr_date) AS date_v,
count(vwr_id) AS views
FROM car_viewer
WHERE Year(vwr_date)='2012' AND vwr_tid='18'
GROUP BY date_v
) as viewz
GROUP BY MONTH_v, YEAR_V
ORDER BY MONTH_v, YEAR_V DESC;
See http://sqlfiddle.com/#!2/75aa8/1 for a working example.

groupby query by year

shipwynum is the primary key for convertship table.
Actually this query getting data correct, for year 2008 only. When i replace 2008 with any other year then also getting data correct for that year. This query display the total records for that year not in TotalCount. TotalCount has always one becoz i have group by with shipwynum.
But i want to get data for 1000 to 2011 separately(instead a particular year like 2008) in this one query and TotalCount should display the counts for every year.
I have this query :=
select
distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s on con.shipwynum = s.shipwynum and s.deleted = 'N'
where left(s.deldat,4) > 1000 and left(s.deldat,4) <= 2008 and
left(con.condat,4) > 2008 and
con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
group by con.shipwynum
Any help or ideas would be greatly appreciated.
Thanks a lot.
I think you're trying to count number of rows for each year?
From what i assume,
there is one main table convertship and you want to join convertship to shipscheduled.
Then do the group by on that data according to its left(con.condat,4) value.
select distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear,
left(con.condat,4) as ConYear
from
convertship con
inner join
shipscheduled s on con.shipwynum = s.shipwynum
where
left(s.deldat,4) > 1000 and
left(s.deldat,4) <= 2008 and
-- left(con.condat,4) > 2008 and
con.deleted = 'N' and
s.deleted = 'N' and
con.wytypid in ('66','10','11','12','13','14','15','16','17','18') and
s.wytypid not in ('66','10','11','12','13','14','15','16','17','18')
group by
left(con.condat,4)
I assume the convertship table is not too big, if not this will not work.
Try:
select count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s
on con.shipwynum = s.shipwynum and
s.deleted = 'N' and
left(s.deldat,4) > 1000 and
left(s.deldat,4) < left(con.condat,4) and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
where con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
group by con.shipwynum, left(s.deldat,4)
Note that since deldat and DeliveryQuarter are neither grouped by nor aggregated, their values in the output will essentially be random (within the DelYear).