Query to select value from another table as a column - mysql

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.

Related

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)

MYSQL: conditional GROUP BY from parameter?

Im trying to code a procedure that groups by a parameter variable, but at this time, its impossible for me. Its possible to do or i'm writting any mistake?
The finally of this procedure is retrieve a list of values, grouped by time periods Whitout the group by line, it works fine. (granularity its a procedure parameter)
SET g = CASE granularity
WHEN 'week' THEN 'WEEK(r.value_date,1),YEAR(r.value_date)'
WHEN 'month' THEN 'MONTH(r.value_date,1),YEAR(r.value_date)'
ELSE 'r.value_date'
END;
INSERT INTO system_temp_points_data (`method`,`value`,`num_rows`,value_date,ref,units_id,unit_name,`hash`,granularity) SELECT
'sum' AS `method`,
SUM(`value`) AS `value`,
COUNT(`value`) AS num_rows,
UNIX_TIMESTAMP(MIN(value_date)) AS value_date,
GROUP_CONCAT(raw_data_id) AS ref,
r.units_id,
u.unit_name,
aux_hash,
granularity
FROM
raw_data r
JOIN temp_unit_group t ON (r.units_id = t.units_id)
JOIN units u ON (t.units_id = u.units_id)
AND (t.start_date <= r.value_date)
AND (t.end_date >= r.value_date)
WHERE
r.value_date BETWEEN start_date
AND end_date
AND kpis_id = kpi
AND IF(exclude_zeros = 1,`value` <> '0',true)
AND IF(value_aux IS NOT NULL,r.aux = value_aux,true)
GROUP BY g
ORDER BY
r.value_date ASC;
The strings in g are not evaluated when it's used in the query. You need to put that condition in the query itself:
GROUP BY CASE granularity
WHEN 'week' THEN WEEK(r.value_date,1)
WHEN 'month' THEN MONTH(r.value_date)
ELSE r.value_date
END,
CASE granularity
WHEN 'week' THEN YEAR(r.value_date)
WHEN 'month' THEN YEAR(r.value_date)
ELSE 1
END
An alternative is to use a prepared statement, and merge g into it:
SET #sql = CONCAT("INSERT INTO system_temp_points_data (`method`,`value`,`num_rows`,value_date,ref,units_id,unit_name,`hash`,granularity) SELECT
'sum' AS `method`,
SUM(`value`) AS `value`,
COUNT(`value`) AS num_rows,
UNIX_TIMESTAMP(MIN(value_date)) AS value_date,
GROUP_CONCAT(raw_data_id) AS ref,
r.units_id,
u.unit_name,
aux_hash,
granularity
FROM
raw_data r
JOIN temp_unit_group t ON (r.units_id = t.units_id)
JOIN units u ON (t.units_id = u.units_id)
AND (t.start_date <= r.value_date)
AND (t.end_date >= r.value_date)
WHERE
r.value_date BETWEEN start_date
AND end_date
AND kpis_id = kpi
AND IF(exclude_zeros = 1,`value` <> '0',true)
AND IF(value_aux IS NOT NULL,r.aux = value_aux,true)
GROUP BY ", g, "
ORDER BY
r.value_date ASC";
PREPARE #stmt FROM #sql;
EXECUTE #stmt;

Prepared Statement: Crosstab dynamic mysql query

I am trying to make a cross tab pivot table. I need to get all teams from the database table dynamically on separate columns instead of specifying names of the teams in the query which I am currently doing. I have looked at another example i.e. MySQL pivot table query with dynamic columns.
At the moment I am receiving the results fine from the database but only by manually typing what column I need in the query. See the example below:
SELECT IFNULL(DATE( date_posted ), 'Total') AS DATE,
SUM(CASE WHEN added_by LIKE '%Team One%' THEN 1 ELSE 0 END) AS Team1,
SUM(CASE WHEN added_by LIKE '%Team Two%' THEN 1 ELSE 0 END ) AS Team2,
COUNT( added_by ) AS Daily_Total FROM teamdata WHERE status LIKE
'%completed%' GROUP BY IFNULL(DATE( date_posted ), 'Total') DESC WITH ROLLUP;
Which displays 4 columns of DATE, Team1, Team2 and Daily_Total. But at a later stage there will be more columns to add in but to be done dynamically. I am trying to execute this prepared statement but to no success:
SET #sql = NULL;
SELECT GROUP_CONCAT( DISTINCT
CONCAT(
'sum(CASE WHEN added_by = ''',
added_by,
''' THEN 1 else ''-'' END) AS `', added_by,
'`'
)
) into #sql
FROM teamdata;
SET #sql
= CONCAT('SELECT IFNULL(DATE( date_posted ), \'Total\') AS DATE, ', #sql, '
from teamdata
WHERE status = \'completed\'
GROUP BY IFNULL(DATE( date_posted ), \'Total\') DESC WITH ROLLUP');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Please could I get further help on this.

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.

what is causing error (operands should contain 1 column)

I am trying to set myItemId so that I can use it in the concat query. Everything works fine until I add this row
SET myItemID = (SELECT * FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
It then gives me an error of
Operand should contain 1 column(s)
Here is the query that I am working with
CREATE PROCEDURE reportFreeCoolingTempTable (
IN fromDate VARCHAR (50),
IN toDate VARCHAR (50),
IN timeZone VARCHAR (50)
)
BEGIN
DECLARE startDate VARCHAR (50);
DECLARE endDate VARCHAR (50);
DECLARE mylogID INT;
DECLARE myItemID int;
SET startDate = FROM_UNIXTIME(fromDate/1000);
SET endDate = FROM_UNIXTIME(toDate/1000);
SET mylogID = (SELECT logID FROM logs WHERE details LIKE 'FCT%' LIMIT 1);
SET myItemID = (SELECT * FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
SET #sql = NULL;
SET #sql = NULL;
SET #sql = CONCAT(
'SELECT #row:=#row+1 as rownum,
a.logid ,
L1.recordId,
L2.recordId as next_recordId,
L1.completed,
L2.completed as next_completed,
L1.activityId,
L2.activityId as next_activityId,
IF(L1.activityId = L2.activityId,1,NULL) as isError,
TIME_TO_SEC(TIMEDIFF(L2.completed, L1.completed)) / 3600 AS coolingHours,
((L1.item31985 - L1.item31987) * (time_to_sec(timediff(L2.completed, L1.completed)))) / 3600 AS kwDifference,
((L1.item31985 - L1.item31987) * (substr(l.details, instr(l.details , '':'' ) +1))) AS cost,
( (((L1.item31985 - L1.item31987) * (substr(l.details, instr(l.details , '':'' ) +1)))
*(time_to_sec(timediff(L2.completed, L1.completed)) / 3600))) AS costT,
time_to_sec(timediff(''', endDate, ''', ''', startDate, ''')) / 3600 AS totalTimeRange,
CONVERT_TZ(''', startDate, ''', ''UTC'', ''', timeZone, ''') AS startingDate,
CONVERT_TZ(''', endDate, ''', ''UTC'', ''', timeZone, ''') AS endingDate,
DATABASE() AS databaseName
FROM
(SELECT #row:=0)R,
(SELECT T1.completed,
(SELECT MIN(completed)
FROM log1644
WHERE completed > T1.completed) AS next_completed
FROM log',mylogID, ' T1
ORDER BY T1.completed
)TimeOrder
LEFT JOIN log', mylogID, ' L1 ON (L1.completed = TimeOrder.completed)
LEFT JOIN log', mylogID, ' L2 ON (L2.completed = TimeOrder.next_completed)
LEFT JOIN activities a ON L1.activityId = a.activityId
LEFT JOIN logs l ON a.logId = l.logId
Left Join items i ON l.logId = i.logId AND i.name LIKE ''%KW%''
WHERE i.itemID = 31985
AND L1.completed BETWEEN ''', startDate, ''' AND ''', endDate, '''
ORDER BY L1.completed');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
Error itself explains (operands should contain 1 column) you need to select the single column from the query in order to set myItemID ,you are selecting all the columns from the items try this
SET myItemID = (SELECT id FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%' LIMIT 1 );
I assume the you need to set the myItemID to the id column from items where you conditions matches.i have also added LIMIT 1 in order to avoid the error of subquery should return one result
The error is caused because the SET statement expects a single value to be returned from your subquery. Not only can it return multiple values (SELECT *), but it can potentially return multiple rows. Change your query to specify just the single column from your subquery that you want to assign to myItemId, and ensure that it can return only 1 row - like this:
SET myItemID = (SELECT TOP 1 [itemIdColumnName] FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
The 'operand' in your case is "myItemID". It can only hold ONE value. Your SELECT statement returns all the rows in the table (multiple columns). You need to select only the 1 column that represents the ID you are trying to obtain.