MySQL loop for total score each week - mysql

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.

Related

Query to select value from another table as a column

I have a query to report some data :
select r.m_id,
count(distinct case when r.sal = '1val' then r.login end) as 1val,
count(distinct case when r.sal = '2val' then r.login end) as 2val,
count(distinct case when r.sal = '3val' then r.login end) as 3val,
...
from read_log r
inner join mes m on m.id = r.m_id
where
YEAR(m.send_date) = YEAR(curdate())
group by r.m_id
r.sal value in count(distinct case when r.sal = '1val' then r.login end) as 1val only changes. Finally it shows results in each column for every r.sal. There are currently over 80 diffrent r.sal and its growing.
My question is:
It is possible to take value for r.sal from another table?
Like new table sal with this 1val, 2val, 3val, 4val, 5val etc...?
Maybe loop or something like that:
count(distinct case when r.sal = (select val from sal) then r.login end)
(I know its wrong but maybe it will illustrate it better)
count(distinct case... is great to show data for each r.sal value in the other column but maybe is another way to achieve that...
CREATE TABLE sal_table (sal CHAR(4));
INSERT INTO sal_table VALUES ('1val'), ('2val'), ... ;
CREATE PROCEDURE get_data ()
BEGIN
SELECT CONCAT (
'select r.m_id, ',
GROUP_CONCAT(
CONCAT(
'count(distinct case when r.sal = ''',
sal,
''' then r.login end) as `',
sal,
'`'
)
),
' from read_log r ',
'inner join mes m on m.id = r.m_id ',
'where YEAR(m.send_date) = YEAR(curdate()) ',
'group by r.m_id'
)
INTO #sql
FROM sal_table;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=af55c52aca3280410fba1f3a453aab09
PS. Recommended edition: WHERE m.send_date >= DATE_FORMAT(CURRENT_DATE, '%Y-01-01') AND m.send_date < DATE_FORMAT(CURRENT_DATE + INTERVAL 1 YEAR, '%Y-01-01'). Such condition is sargable rather than your one.

Use the result of a MySQL query, as a variable, with the IN-operator

Looking for a way to return a variable that can be used inside a IN-operator.
My current result returns: 1,2,3,
but I guess the variable should be more like this: '1','2','3' to be able to use it.
Is this possible?
Or should I try something else like explode, save the query,...
-- init vars
SET #export_date = '2022-06-20';
SET #order_ids = '';
-- Tasks on given day
SELECT * FROM tasks WHERE task_execution_date = #export_date;
-- method 1
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT task_order SEPARATOR ',' ) FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- method 2
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT '' + cast( task_order AS CHAR(50)) +'' ) FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- method 3
SET #order_ids = (SELECT GROUP_CONCAT( DISTINCT + '\'' + CAST(task_order AS CHAR (100)) + '\'') FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- Orders by tasks
SELECT * from orders WHERE ordr_id IN (#order_ids); -- returns only one result
-- SELECT * from orders WHERE ordr_id IN #order_ids; -- error
SELECT * from orders WHERE ordr_id IN ('1', '2', '3'); -- works
SELECT * from orders WHERE ordr_id IN (SELECT DISTINCT task_order FROM tasks WHERE task_execution_date = #export_date); -- works
-- Also needed:
-- goods by orders
-- good_adrs by goods
If You really, really, I mean REALLY know that these variables can't be evil, then You can build and execute raw query:
SET #export_date = '2022-06-20';
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT task_order SEPARATOR ',' ) FROM tasks WHERE task_execution_date = #export_date);
SET #query = CONCAT('SELECT * from orders WHERE ordr_id IN (', #order_ids, ');');
PREPARE stmt FROM #query;
EXECUTE stmt;

SQL Counting Distinct Values From Table With multiple Where possibilities [duplicate]

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
MySQL pivot table query with dynamic columns
(3 answers)
Closed 3 years ago.
The question is simple. How do i combine the following 2 sql queries into one.
I am using MYSQL v8.0.16 on the MYSQL Workbase UI.
SELECT Node_Type, COUNT(*) AS `count`
FROM node_table_vis
WHERE Node_SpinePlanID = "1"
GROUP BY Node_Type;
RETURNS
TYPE - COUNT
-----------
AGN 18
TJ 26
DSLAM 15
PON 18
CCJ 17
and
SELECT DISTINCT Node_SpinePlanID
FROM node_table_vis
WHERE Node_Exchange = "Exchange 1";
Thats returns
SpinePlanID
------------
1
5
10
So essentially what i want is query that looks like this?
SELECT Node_Type, COUNT(*) AS `count`
FROM node_table_vis
WHERE Node_SpinePlanID =
(
SELECT DISTINCT Node_SpinePlanID
FROM node_table_vis
WHERE Node_Exchange = "Exchange 1";
)
GROUP BY Node_Type;
So I get table that looks like
TYPE - 1 - 5 - 10
-----------------------
AGN 18 x y
TJ 26 x y
DSLAM 15 x y
PON 18 x y
CCJ 17 x y
So this is just throwing errors and not producing the goods. I was able to find the answer the top query, i was able to make the bottom, however i am unable to find an answer to combine both.
Any advice would be really appreciated.
UPDATE/EDIT
I have the following ...
SET ##group_concat_max_len = 10000;
SET #sql = null;
SELECT group_concat(distinct
concat(
'SUM(Node_SpinePlanID = ''',
Node_SpinePlanID,
''',) AS ',
Node_SpinePlanID
)
) INTO #sql
FROM node_table_vis;
SET #sql = CONCAT('SELECT Node_Type, ', #sql, ' FROM node_table_vis GROUP BY Node_Type');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
However the PREPARE stmt is not working? Getting error Code 1064 You have an SQL Error Syntax?
Any Advice on this one?
Are you looking for conditional aggregation?
SELECT Node_Type,
SUM(Node_SpinePlanID = 1) AS count_1,
SUM(Node_SpinePlanID = 5) AS count_5,
SUM(Node_SpinePlanID = 10) AS count_10
FROM node_table_vis
GROUP BY Node_Type;
You can also put the values into rows:
SELECT Node_Type, Node_SpinePlanID, COUNT(*) as cnt
FROM node_table_vis
GROUP BY Node_Type, Node_SpinePlanID;
Without dynamic SQL, probably the best you can do is to put the values in a single row is to put them in a string with two levels of aggregation:
SELECT Node_Type, GROUP_CONCAT(Node_SpinePlanID, ':', cnt SEPARATOR ',')
FROM (SELECT Node_Type, Node_SpinePlanID, COUNT(*) as cnt
FROM node_table_vis
GROUP BY Node_Type, Node_SpinePlanID
) ts
GROUP BY Node_Type;

Error Code: 1052 - Column 'idk' in field list is ambiguous

Hi I trying to create query and add this, query error:
JOIN matakuliah ON nilai.idk = matakuliah.idk
WHERE matakuliah.semester = 1
full query:
SET #sql_dinamis = ( SELECT GROUP_CONCAT( DISTINCT CONCAT( 'max( IF(idk = ', idk, ',huruf,null) ) AS A', idk ) ) FROM nilai );
SET #SQL = CONCAT( 'SELECT mahasiswa.nim, mahasiswa.nama, ', #sql_dinamis, '
FROM nilai
JOIN mahasiswa ON nilai.idm = mahasiswa.idm
JOIN matakuliah ON nilai.idk = matakuliah.idk
WHERE matakuliah.semester = 1
GROUP BY nilai.idm' );
PREPARE stmt
FROM
#SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
error message:
FROM nilai
JOIN mahasiswa ON nilai.idm = mahasiswa.idm
JOIN matakuliah ON nilai.idk = matakuliah.idk
WHERE matakuliah.semester = 1
GROUP BY nilai.idm' )
> OK
> Time: 0s
PREPARE stmt
FROM
#SQL
> 1052 - Column 'idk' in field list is ambiguous
> Time: 0s
help me to solve this.
this my database https://irhas.online/test/test2.txt please help me.
Your query has a reference to idk (from the #sql_dinamis part) however both your nilai and matakuliah have idk fields in them, so SQL doesn't know which one you want. You need to change the idk in
SET #sql_dinamis = ( SELECT GROUP_CONCAT( DISTINCT CONCAT( 'max( IF(idk = ', idk, ',huruf,null) ) AS A', idk ) ) FROM nilai );
to be either nilai.idk or matakuliah.idk e.g.
SET #sql_dinamis = ( SELECT GROUP_CONCAT( DISTINCT CONCAT( 'max( IF(nilai.idk = ', idk, ',huruf,null) ) AS A', idk ) ) FROM nilai );
This works for me (see DBFiddle)

SESSION group_concat_max_len size is not enough, it gives a different error when changing the size

So I am making a stored procedure in MySQL that accepts an integer _prof_id. This code is for changing my rows to columns dynamically.
Here is my code
DELIMITER $$
CREATE PROCEDURE Get_Attendance(IN _profID INT)
BEGIN
SET SESSION group_concat_max_len = 18446744073709547520;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(date = ''',
date,
''', status_description, NULL)) AS ',
date
)
) INTO #sql
FROM current_att_view;
SET #sql = CONCAT(
'SELECT a.professor_fname, a.professor_lname, ', #sql,
' FROM professor_tbl m JOIN current_att_view a
ON m.professor_id = a.professor_id
WHERE m.professor_id = ', _profID,' Group BY entity_ID');
PREPARE stmt FROM #sql;
EXECUTE stmt;
END$$
DELIMITER ;
so I have researched and found out that 18446744073709547520 is the maximum value for the group_concat_max_len and it cannot be unlimited. but when I call the procedure, it gives me an error
Mysql Error Image, which came from the 24th and 25th row of my table 24th and 25th row of table image. There are still plenty of rows to concatenate. What should I do? Or are there any other way in order for me to change the rows to columns dynamically?
so my current_att_view (Which is a created view) structure is current_att_view and the professor table structure is like this Professor Table and I want to generate a query that would make a table structure like this
Table Structure
When I tried my code for group concat, the output is shown as output
Here's a guess how a simplified version of your data looks
drop table if exists current_att_view,professor_tbl;
create table current_att_view
(attendanceid int auto_increment primary key,
entity_id int,
Professor_id int,
dte date,
status_description varchar(8));
create table professor_tbl
(professor_id int, professor_fname varchar(20), professor_lname varchar(20));
insert into current_att_view (entity_id ,
Professor_id ,
dte ,
status_description) values
(1,1,'2018-01-01','Present'),(1,1,'2018-01-02','Absent'),(1,1,'2018-01-03','Present'),
(2,1,'2018-01-01','Absent'),(2,1,'2018-01-02','Absent'),(2,1,'2018-01-03','Present');
insert into professor_tbl values
(1,'bob','smith'),(2,'fred','jones');
select p.professor_fname,p.professor_lname, dte,status_description
from professor_tbl p
join current_att_view a on a.professor_id = p.professor_id
This procedure
drop procedure if exists p;
DELIMITER $$
CREATE PROCEDURE p(IN _profID INT)
BEGIN
SET SESSION group_concat_max_len = 18446744073709547520;
#SET SESSION group_concat_max_len = 1024;
SET #sql = NULL;
set #sql = (
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('MAX(IF(dte = ', char(39),dte,char(39), ', status_description , null)) AS ', char(39),dte,char(39))
)
from current_att_view
);
select length(#sql);
SET #sql = CONCAT(
'SELECT m.professor_lname,m.professor_fname,entity_id ,', #sql,
' FROM professor_tbl m JOIN current_att_view a
ON m.professor_id = a.professor_id
WHERE m.professor_id = ', _profID,' Group BY m.professor_lname,m.professor_fname,entity_id ');
#set #sql = concat('select ',#sql,' from attendance;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
deallocate prepare stmt;
END$$
DELIMITER ;
Generates this query
SELECT m.name,entity_id ,MAX(IF(dte = '2018-01-01', status_description , null)) AS '2018-01-01',
MAX(IF(dte = '2018-01-02', status_description , null)) AS '2018-01-02',
MAX(IF(dte = '2018-01-03', status_description , null)) AS '2018-01-03'
FROM professor_tbl m
JOIN current_att_view a ON m.id = a.professor_id
WHERE m.id = 1 Group BY m.name, a.entity_ID;
Which produces this result (as expected)
-----------------+-----------------+-----------+------------+------------+------------+
| professor_lname | professor_fname | entity_id | 2018-01-01 | 2018-01-02 | 2018-01-03 |
+-----------------+-----------------+-----------+------------+------------+------------+
| smith | bob | 1 | Present | Absent | Present |
| smith | bob | 2 | Absent | Absent | Present |
+-----------------+-----------------+-----------+------------+------------+------------+
2 rows in set (0.01 sec)
I don't think I can help you any further.
Not an answer more an extended comment.This code works fine for every day in 2016-2017 (albeit very slowly) ie 730 days which seems to be more than you would need. I think this proves there is no group_concat truncation on my 64bit box where max_allowed_packed is default 4194304 at least.
drop procedure if exists p;
DELIMITER $$
CREATE PROCEDURE p(IN _profID INT)
BEGIN
SET SESSION group_concat_max_len = 18446744073709547520;
#SET SESSION group_concat_max_len = 1024;
SET #sql = NULL;
set #sql = (
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('MAX(IF(dte = ', char(39),dte,char(39), ', 1, 0)) AS ', char(39),dte,char(39))
)
from dates
where year(dte) in(2016,2017)
);
/*
SET #sql = CONCAT(
'SELECT a.professor_fname, a.professor_lname, ', #sql,
' FROM professor_tbl m JOIN current_att_view a
ON m.professor_id = a.professor_id
WHERE m.professor_id = ', _profID,' Group BY entity_ID');
*/
set #sql = concat('select ',#sql,' from dates;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
deallocate prepare stmt;
END$$
DELIMITER ;
call p(1);