Mysql attendence report creates syntax error on prepare stmt - mysql

I have two tables: One with just a list of dates called date_range (column name is Date) and one called wp_wpdatatable_1 in which all the date is stored (after each practice, a row for every player is created with the name of the player (player), date of practice (date), duration (sporttrainingduration), what practice group (practiceheldby) etc...
Now I want to create a report.
I want every day of the month across, the players names in the first column and on every day a player was at a practice I want to list which practice he attended (wp_wpdatatable_1.practiceheldby)
-- 1. Create an expression that builds the columns
set #sql = (
select group_concat(distinct
concat(
"max(case when date_range.`date`='", date_range.`Date`, "' then `practiceheldby` end) as `", date_range.`Date`, "`"
)
)
from wp_wpdatatable_1, date_range
where date_range.`Date`>=2019-06-01
and date_range.`Date` <= 2019-06-07
);
-- 2. Complete the SQL instruction
set #sql = concat("select `player`, ", #sql , " from wp_wpdatatable_1 group by `player`");
-- 3. Create a prepared statement
PREPARE stmt from #sql;
-- 4. Execute the prepared statement
execute stmt;
DEALLOCATE PREPARE stmt;
I'm not a pro and I've played with this for 3 or four days now. I think I'm very close, but I get this error message:
PREPARE stmt from #sql
MySQL meldet: Dokumentation
#1064 - Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen bei 'NULL' in Zeile 1
What am I missing?
thank you!

You're very close. Besides the missing quotes on dates, the case when date_range.date should be case when date in line 5 of your code.
-- 0. Toy data
CREATE TABLE date_range (
`Date` datetime
);
CREATE TABLE wp_wpdatatable_1 (
`player` VARCHAR(5),
`Date` DATE,
`sporttrainingduration` FLOAT,
`practiceheldby` VARCHAR(10)
);
INSERT INTO date_range
VALUES
('2019-06-01'),
('2019-06-02'),
('2019-06-03')
;
INSERT INTO wp_wpdatatable_1
VALUES
('AAA','2019-06-01','1','group1'),
('AAA','2019-06-02','2','group2'),
('AAA','2019-06-03','3','group3'),
('AAA','2019-06-04','1','gorup1'),
('BBB','2019-06-02','2','group2'),
('CCC','2019-06-03','3','group3')
;
select * from date_range;
select * from wp_wpdatatable_1;
date_range
===================
Date
===================
2019-06-01 00:00:00
2019-06-02 00:00:00
2019-06-03 00:00:00
wp_wpdatatable_1
=======================================================
player Date sporttrainingduration practiceheldby
=======================================================
AAA 2019-06-01 1 group1
AAA 2019-06-02 2 group2
AAA 2019-06-03 3 group3
AAA 2019-06-04 1 gorup1
BBB 2019-06-02 2 group2
CCC 2019-06-03 3 group3
The updated code below:
-- 1. Create an expression that builds the columns
set #sql = (
select group_concat(distinct
concat(
-- "max(case when date_range.`date`='", date_range.`Date`, "' then `practiceheldby` end) as `", date_range.`Date`, "`"
"max(case when `date`='", date_range.`Date`, "' then `practiceheldby` end) as `", date_range.`Date`, "`"
)
)
from wp_wpdatatable_1, date_range
-- where date_range.`Date`>=2019-06-01
-- and date_range.`Date` <= 2019-06-07
where date_range.`Date`>='2019-06-01'
and date_range.`Date` <= '2019-06-07'
);
Output:
===========================================================================
player 2019-06-01 00:00:00 2019-06-02 00:00:00 2019-06-03 00:00:00
===========================================================================
AAA group1 group2 group3
BBB null group2 null
CCC null null group3
Code here

Related

How to pivot record based on week number in mysql?

I can easily pivot the result date wise but unable to do same in week number wise.
The table structure exp.
CREATE TABLE `products` (
`product_name` varchar(250) DEFAULT NULL,
`date` date DEFAULT NULL,
`sales` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*Data for the table `products` */
insert into `products`(`product_name`,`date`,`sales`) values
('Micro','2020-08-01',100),
('Micro','2020-08-02',200),
('x','2020-08-02',300),
('y','2020-08-01',300),
('z','2020-08-03',400),
('x','2020-08-03',400),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-10',500),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-10',500),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-11',230),
('y','2020-08-11',210),
('z','2020-08-11',240);
The query for showing sum of sale by date wise as below mysql code i used
SET SESSION group_concat_max_len = 10000;
DROP TEMPORARY TABLE IF EXISTS temp_sale;
CREATE TEMPORARY TABLE temp_sale
SELECT `date`,product_name,SUM(sales) AS sales FROM
products
WHERE DATE BETWEEN DATE_ADD("2020-08-12",INTERVAL -29 DAY) AND "2020-08-12"
GROUP BY `date`,product_name;
SELECT * FROM temp_sale;
// this code is used to get the result on date wise pivot
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN date = ''',
DATE_FORMAT(DATE, '%Y-%m-%d'),
''' THEN round(sales,2) end) AS `',
DATE_FORMAT(DATE, '%Y-%m-%d'), '`'
)
) INTO #sql
FROM `temp_sale` WHERE DATE BETWEEN DATE_ADD("2020-08-12",INTERVAL -29 DAY) AND "2020-08-12" ;
SET #final_query = CONCAT('select product_name,',#sql,' from temp_sale
group by product_name');
PREPARE stmt FROM #final_query;
EXECUTE stmt;
and output for the above query like as below
But the problem is that i need to sum the sum of sales record by week wise. like as
Product_name | sales | week-31 | week- 32 | week- 33
Please help here in pivot data by week number dynamically.
This pivot table makes that what you want without temporary table
CREATE TABLE `products` (
`product_name` varchar(250) DEFAULT NULL,
`date` date DEFAULT NULL,
`sales` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*Data for the table `products` */
insert into `products`(`product_name`,`date`,`sales`) values
('Micro','2020-08-01',100),
('Micro','2020-08-02',200),
('x','2020-08-02',300),
('y','2020-08-01',300),
('z','2020-08-03',400),
('x','2020-08-03',400),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-10',500),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-10',500),
('y','2020-08-10',500),
('z','2020-08-10',500),
('x','2020-08-11',230),
('y','2020-08-11',210),
('z','2020-08-11',240);
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN date = ''',
DATE_FORMAT(DATE, '%Y-%m-%d'),
''' THEN round(sales,2) end) AS `',
DATE_FORMAT(DATE, '%Y-%m-%d'), '`'
)
) INTO #sql
FROM `temp_sale` WHERE DATE BETWEEN DATE_ADD("2020-08-12",INTERVAL -29 DAY) AND "2020-08-12" ;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WEEK(`date`) WHEN "',
WEEK(`date`),
'" THEN `sales` ELSE 0 END) AS `',
CONCAT('week-',WEEK(`date`)), '`'
)
ORDER BY WEEK(`date`)
)
INTO #sql
FROM products as p
SET #sql = CONCAT('select product_name,SUM(`sales`), ',#sql,' from products
group by product_name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
product_name | SUM(`sales`) | week-30 | week-31 | week-32
:----------- | -----------: | ------: | ------: | ------:
Micro | 300 | 100 | 200 | 0
x | 1930 | 0 | 700 | 1230
y | 2010 | 300 | 0 | 1710
z | 2140 | 0 | 400 | 1740
db<>fiddle here

pivot with dynamic date columns in SqlServer 2012 & MySQL

I have below data.
create table #temp
(
date date primary key
,registrations int not null default(0)
,orders int not null default(0)
)
insert into #temp
(
date ,
registrations
,orders
)values('2017-05-01',30,40),('2017-05-02',60,30),('2017-05-03',109,98)
select * from #temp
for each date the data will keep on add. It is very dynamic. Is there anyway to pivot the data with dynamic dates if #from_dt and #to_dt provided as paramters. Output should look like below.
2017-05-01 2017-05-02 2017-05-03
registrations 30 60 109
orders 40 30 98
I have same data in SQLServer and MySQL databases.
any help is appreciated. Thanks in advance.
Declare #Date1 date = '2017-05-01'
Declare #Date2 date = '2017-05-02' -- Notice only Two Days
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName([Date]) From #temp Where [Date] between #Date1 and #Date2 Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
select [Date]
,B.*
From #temp
Cross Apply (values (''Orders'',orders)
,(''Registrations'',registrations)
) B(Item,Value)
Where [Date] between '''+convert(varchar(10),#Date1,120)+''' and '''++convert(varchar(10),#Date2,120)+'''
) A
Pivot (sum(Value) For [Date] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
Item 2017-05-01 2017-05-02
Orders 40 30
Registrations 30 60

How to fetch row value as a column name In Mysql

I need help with below scenario. How can we get distinct values in rows as column Names dynamically?
I have data in below format..
Sno firstName Subject Marks
1 ABC Eng 10
2 PQR Hindi 20
3 LM Telgu 20
4 LM Hindi 20
5 LM Eng 39
I need output in below format.
Sno FirstName Eng Hindi Telgu
1 ABC 10 Null Null
2 PQR Null 20 Null
3 LM 39 20 20
If one more subject is added, query should be written dynamic enough to include those values too..
How can Write Query for This?
Hi there as Abecee told you in comment solution for your problem is pivoting table.
Here is query for your table
SELECT Sno, firstName,
SUM(CASE WHEN Subject = 'Eng' THEN Marks ELSE NULL END) AS Eng,
SUM(CASE WHEN Subject = 'Hindi' THEN Marks ELSE NULL END) AS Hindy,
SUM(CASE WHEN Subject = 'Telgu' THEN Marks ELSE NULL END) AS Telgu
FROM t1
GROUP BY firstName
ORDER BY Sno
And here is SQL Fiddle to see how it's work...
GL!
Edit:
Ok based on this bluefeet answer here is dynamics solution for your problem
SET #sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SUM(CASE WHEN Subject = ''',
Subject,
''' THEN Marks ELSE NULL END) AS ',
REPLACE(Subject, ' ', ''))) INTO #sql
FROM t1;
SET #sql = CONCAT('SELECT Sno, firstName, ', #sql, '
FROM t1
GROUP BY firstName
ORDER BY Sno');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
First part of this
SET #sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SUM(CASE WHEN Subject = ''',
Subject,
''' THEN Marks ELSE NULL END) AS ',
REPLACE(Subject, ' ', ''))) INTO #sql
FROM t1;
is to dynamically create this part of first query I wrote
SUM(CASE WHEN Subject = 'Eng' THEN Marks ELSE NULL END) AS Eng,
SUM(CASE WHEN Subject = 'Hindi' THEN Marks ELSE NULL END) AS Hindy,
SUM(CASE WHEN Subject = 'Telgu' THEN Marks ELSE NULL END) AS Telgu
the second part is to create prepared statement and to include dynamically created part into this
SELECT Sno, firstName,
-- here you add dynamically created part #sql
FROM t1
GROUP BY firstName
ORDER BY Sno
you do that with CONCAT in this part of code
SET #sql = CONCAT('SELECT Sno, firstName, ', #sql, '
FROM t1
GROUP BY firstName
ORDER BY Sno');
when you create that from that string you prepare statement and execute it
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Hope that is a little bit clear now...
Here is SQL Fiddle so you can see that you can compare both query and see how it's work..
GL!
P.S. if you have any question fill free to ask in comment bellow

MySQL loop for total score each week

The following statement outputs the userName and week1Score. I would like it to loop through 17 times, to get the score for each of the 17 weeks.
SELECT userName, (totalWins+(totalPushs*.5)) AS week1Score FROM (
SELECT *, SUM(win) AS totalWins, SUM(lost) AS totalLost, SUM(push) AS totalPushs FROM (
SELECT *, (finalResult = 'win') AS win, (finalResult = 'loss') AS lost, (finalResult = 'push') AS push FROM (
SELECT userName, IF (pickID=visitorID, visitorResult, homeResult) AS finalResult
FROM table_users
JOIN table_picks
ON table_users.userID = table_picks.userID
JOIN table_schedule
ON table_picks.gameID = table_schedule.gameID
WHERE weekNum = 1
) x
) x GROUP BY userName
) x ORDER BY userName
The above statement outputs the following.
+-----------------------+
| userName | week1Score |
+-----------------------+
I would like it to loop through 17 times to to output the following.
+------------------------------------------------------------------------+
| userName | week1Score | week2Score | week3Score | week4Score | week... |
+------------------------------------------------------------------------+
How would I use MySQL loop to do this?
I think your query is a bit complex. However, there's a better approach: a Pivot Query.
MySQL does not have a "pivot" instruction, but an expression can be built to get the output you need.
I'll build a temp table to make things a bit easier to read (I am using user variables to make things a bit clearer):
-- This first table will compute the score
drop table if exists temp_step01;
create temporary table temp_step01
select userId
, userName
, weekNum
, #finalResult := if(pickId=visitorId, visitorResult, homeResult) as finalResult
, #w := #finalResult = 'win' as win
, #l := #finalResult = 'loss' as lost
, #p := #finalResult = 'push' as push
, #w + (#p * 0.5) as score
from
table_users as tu
join table_picks as tp on tu.userId = tp.userId
join table_schedule as ts on tp.gameId = ts.gameId;
alter table temp_step01
add index uid(userId),
add index wn(weekNum);
Now, the fun part: build the pivot table
-- First, build the expression for each column
select
group_concat(
concat(
'sum(case weekNum when ', weekNum, ' then score end) as week', weekNum, 'score'
)
)
into #sql
from (select distinct weekNum from temp_step01) as a;
-- Then, create a complete SELECT statement
set #sql = concat('select userId, userName, ', #sql, ' from temp_step01 group by userId');
-- OPTIONAL: Check that the sql statement is well written:
select #sql;
-- Now, prepare a statement, and execute it
prepare stmt from #sql;
execute stmt;
-- When you're done, don't forget to deallocate the statement
deallocate prepare stmt;
A bit laborious, but I think this will give you what you need. Hope it helps.

SQL query with dynamic columns (PIVOT)

I am trying to write a SQL query that will turn this table:
Start_time End_time Instructor Student
9:00 9:35 Joe Bob Andrew
9:00 9:35 Joe Bob Smith
9:00 9:35 Roberto Andy
10:00 10:35 Joe Bob Angelica
11:00 11:20 Roberto Bob
Into something like this:
Instructor 9:00 10:00 11:00
Joe Bob Andrew, Smith Angelica NULL
Roberto Andy NULL Bob
I think that this is some sort of PIVOT command but I am not sure how I should go about writing the SQL query. The times are all dynamically generated so I would prefer it if the query would generate the column names in the second table dynamically (for example, if the original table contained an additional start time of 11:30, there should be a new column for 11:30 in the result).
Thank you in advance, I've been playing with this for a while but couldn't get it to work on my own. I can provide the SQL INSERT commands to give you the full data if necessary.
EDIT: It would be particularly helpful to get the result of this select statement as a VIEW. Thanks!
EDIT 2:
The code that is generating the view that makes the first table is:
CREATE VIEW schedule_view AS SELECT RTRIM(SUBSTRING(students.schedule_first_choice, 1, 5)) AS start_time, RTRIM(SUBSTRING(students.schedule_first_choice, -10, 5) AS end_time, CONCAT(instructors.first_name, ' ', instructors.last_name) AS instructor_name,
CONCAT(students.first_name, ' ', students.last_name) AS student_name , students.swim_america_level as class
FROM students, instructors WHERE students.instructor_id = instructors.instructor_id AND students.season =
(SELECT constant_value FROM constants WHERE constant_name = 'season') AND students.year =
(SELECT constant_value FROM constants WHERE constant_name = 'year')
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'GROUP_CONCAT(case when Start_time = ''',
Start_time,
''' then Student ELSE NULL end) AS ',
CONCAT('`',Start_time,'`')
)
) INTO #sql
FROM Table1;
SET #sql = CONCAT('SELECT Instructor, ', #sql, '
FROM Table1
GROUP BY Instructor');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SQLFiddle Demo
IN THESE ALL QUERY EXECUTED AND TESTED IN SQL SEREVR
USING STATIC COLUMNS IN PIVOT
Select * from
(
select Instructor,Start_time, STUFF((select ',' + student from Table1 a where
a.Start_time = b.Start_time and
a.Instructor=b.Instructor for xml path('')),1,1,'') as student
from table1 b ) x
PIVOT
(
max(Student)
for start_time IN ([9:00],[10:00], [11:00])
) p
DYNAMICALLY CREATE PIVOT TABLE Using Temp Table
Declare #tab nvarchar(max)
Declare #pivottab nvarchar(max)
Create table #Table2 (
instructor varchar(100),
student varchar(100),
start_time varchar(10)
);
insert into #Table2 (instructor,student,start_time)
select
Instructor,
STUFF((Select ','+student
from Table1 as a
Where
a.Start_time = b.Start_time and
a.Instructor=b.Instructor
for xml path('')),1,1,''),
Start_time
from table1 as b
select #tab = coalesce(#tab + ',['+start_time+']' ,'['+start_time+']')
from #Table2
group by Start_time
set #pivottab =
N' select * from (
select Instructor, Start_time, student from #Table2
) x
PIVOT (
max(Student) for start_time IN ('+#tab+')
) p'
execute(#pivottab)
if exists(select * from #table2)
Begin
Drop table #table2
End
DYNAMICALLY CREATE PIVOT TABLE
Declare #tab nvarchar(max)
Declare #pivottab nvarchar(max)
Select #tab = coalesce(#tab + ',['+start_time+']' , '['+start_time+']') from Table1
group by Start_time
set #pivottab = N'
select *
from
(
select Instructor,Start_time,STUFF((select '+ char(39)+char(44)+char(39) + '+ a.student from Table1 as a
where a.Start_time = b.Start_time and a.Instructor=b.Instructor for xml path('''')),1,1,'''')
as Student from table1 as b
) x
PIVOT
(
max(Student)
for start_time IN ('+#tab+')
) p'
execute(#pivottab)