just playing around with some sql statements on MYSQL Server 5.1
I already asked a question how to make a specific count on two tables (see here)
and I also found an answer how to transpose my result (see here) but I cant use it on my local MYSQL Server 5.1.
This is table one: test
id|name|test_type
-------------
1|FirstUnit|1
2|FirstWeb|2
3|SecondUnit|1
The second table: test_type
id|type
--------
1|UnitTest
2|WebTest
The following result will be written into "yourtable" (a temporary table)
type|amount
-----------
UnitTest|2
WebTest|1
What I want to have at the end is:
UnitTest|WebTest
-----------------
2|1
(The problem is I think, the the last part is from an MS-SQL example, so it will not work on MYSQL)
This are my sql statements:
--create a temporary table
create temporary table IF NOT EXISTS yourtable
(
test_type varchar(255),
amount varchar(255)
);
--make a selecten into the temporary table
INSERT INTO yourtable
SELECT
t.test_type ,
COUNT(*) AS amount
FROM test_types AS t
JOIN test AS te ON t.id= te.test_type
GROUP BY test_type
ORDER BY t.test_type;
--just for debugging
select * from yourtable;
-- transpose result
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Type)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + ' from
(
select Type, Amount,
row_number() over(partition by Type order by Type, Amount) rn
from yourtable
) x
pivot
(
max(Amount)
for Type in (' + #cols + ')
) p '
execute(#query)
--drop temporary table
drop table yourtable;
I can't run the last part where I want to transpose my temporary result. I get an error for "DECLARE"
/* SQL Error (1064): You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right
syntax to use near 'DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = ' at line 2 / / 2 rows affected, 2 rows found.
Duration for 3 of 4 queries: 0,000 sec. */
Can anybody help?
MySQL Does not have a pivot function so you will have to transpose the data from rows into columns using an aggregate function with a CASE expression:
select
sum(case when tt.type = 'UnitTest' then 1 else 0 end) UnitTest,
sum(case when tt.type = 'WebTest' then 1 else 0 end) WebTest
from test t
inner join test_type tt
on t.test_type = tt.id
See SQL Fiddle with Demo.
If you are going to have an unknown number of types that you want to convert to columns, you can use a prepared statement to generate dynamic SQL:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'sum(CASE WHEN tt.type = ''',
type,
''' THEN 1 else 0 END) AS `',
type, '`'
)
) INTO #sql
FROM test_type;
SET #sql
= CONCAT('SELECT ', #sql, '
from test t
inner join test_type tt
on t.test_type = tt.id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo
Related
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;
I have a table called tbl_site with 50 columns. I want to write some SQL code that will count the number of distinct values and the number of null values for each column without having to run a statement for each column.
I understand this would possibly include running a nested query to information_schema.columns but I am unsure on how to construct the query further. Also null values would include values that are '' and ' ' if possible.
The desired output would be the following:
Column | Distinct | Null
site_id | 100 | 0
sitearea_id | 12 | 0
site_area | 54 | 5
etc....
Try a mixture of count distinct and sum case:
SELECT Column, count(distinct Column) as 'Distinct'
,sum(case when Column is null then 1 else 0 end) as 'Null'
FROM tbl_site
GROUP BY 1
Yeah, I noticed it's MySQL after i made a script for SQL Server ... but anyway here is the code in case someone needs it ... or if you get idea from it how to do it
declare #position int = 1,
#sql nvarchar(max),
#columnCnt int,
#currentColumn nvarchar(50),
#TableName nvarchar(50) = 'YourTableName',
#DBName nvarchar(50) = 'YourDbName';
if (OBJECT_ID('tempdb..#MyRowCount')) IS NOT NULL DROP TABLE #MyRowCount
CREATE TABLE #MyRowCount (ColumnName nvarchar(50), DistinctCount int, NullCount int)
set #columnCnt = (select MAX(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and TABLE_CATALOG = #DBName)
WHILE (#position <= #columnCnt)
BEGIN
set #currentColumn = (select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and
TABLE_CATALOG = #DBName and
ORDINAL_POSITION = #position)
set #sql = 'INSERT INTO #MyRowCount (ColumnName, DistinctCount, NullCount)
SELECT ''' + #currentColumn + ''',
(SELECT COUNT(DISTINCT [' + #currentColumn + ']) FROM ' + #TableName + ' where [' + #currentColumn + '] IS NOT NULL),
(SELECT COUNT(*) FROM ' + #TableName + ' where [' + #currentColumn + '] IS NULL)';
-- print #sql;
execute (#sql);
set #position = #position + 1;
END
SELECT * FROM #MyRowCount
In MySQL, you can construct the query using:
set #sql = '
select ''[column]'' as col, count(distinct "[column]"), sum("[column]" is null)
from [table] t
';
select group_concat(replace(replace(#sql, '[table]', table_name), '[column]', column_name) separator ' union all ')
from information_schema.columns
where table_name = ?;
The caveat to this approach is that you need to be sure that your group_concat maximum length value is long enough (the default of 1024 won't get you very far).
Then, you can either copy the query to use prepare/execute to run it.
This question already has answers here:
MySQL - Rows to Columns
(13 answers)
MySQL pivot table query with dynamic columns
(3 answers)
Closed 4 years ago.
I have a table like this:
id key year month value
---------------------------------------
1 AD 2000 1 5465
2 AD 2000 2 6445
3 JK 2000 1 7777
4 JK 2000 2 9999
I need to retrive the values like this:
key 2000-1 2000-2
------------------------
AD 5465 6445
JK 7777 9999
I'm having issues with creating the headers, concatenating year and month and displaying the value under the header.
I have another pivot procedure like this:
SELECT
GROUP_CONCAT(
DISTINCT CONCAT(
'MAX(IF(combustible_id = ''',
combustible_id,
''', valor_combustible, NULL)) AS ',
CONCAT("`",admin_combustibles.nombre,"`")
)
) INTO #SQL
FROM
admin_indice_combustibles
INNER JOIN admin_combustibles
ON admin_indice_combustibles.combustible_id = admin_combustibles.id_combustible
WHERE admin_indice_combustibles.estado = 1;
SET #SQL = CONCAT(
'SELECT anio, mes, ',
#SQL,
' FROM admin_indice_combustibles
WHERE estado = 1
GROUP BY anio, mes
ORDER BY id_indice_combustible'
);
PREPARE stmt
FROM
#SQL;
it is working, but it uses more data (because it has a JOIN with another table), now is easier, all the data is in just 1 table, but I can't get it. any hint please?
EDIT:
I'm trying with this code:
BEGIN
SELECT
GROUP_CONCAT(
DISTINCT CONCAT(
' MAX(IF(anio = ''',
DIST.anio,
''' AND mes = ''', DIST.mes, ''', energia_adjudicada_mwh, NULL)) AS ',
CONCAT("`",DIST.anio,"-`", DIST.mes,"`")
)
) INTO #SQL
FROM
admin_contratos_energia_adjudicadas_distribucion_mensual AS DIST
WHERE DIST.activo = 1;
SET #SQL = CONCAT(
'SELECT DIST.key, DIST.contrato_id ',
#SQL,
' FROM admin_contratos_energia_adjudicadas_distribucion_mensual AS DIST
WHERE activo = 1
GROUP BY DIST.key
ORDER BY DIST.contrato_id ');
PREPARE stmt
FROM
#SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
I'm getting the error:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MAX(IF(anio = '2016' AND mes = '1', energia_adjudicada_mwh, NULL)) AS 2016-1`,' at line 1
I just need to concatenate the year (anio) and month (mes) in the header, and give the value (energia_adjudicada_mwh) to them, for each year and mont, group by key...
This is the table that I have and the table that I need:
Use conditional aggregation like this:
SQL DEMO
SELECT `key`,
MAX( CASE WHEN `year` = 2000 and `month` = 1 THEN `value` END) as `2000-01`,
MAX( CASE WHEN `year` = 2000 and `month` = 2 THEN `value` END) as `2000-02`
FROM t49613951
GROUP BY `key`;
OUTPUT:
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.
I have below database table : Table name - dim_module
id Creation_Date Goals Alternative Value
-----------------------------------------------------------
1 2014-04-17 10:09:30 G1 A 0.86
2 2014-04-17 10:09:30 G1 B 0.87
3 2014-04-17 10:09:30 G2 A 0.5
4 2014-04-17 10:09:30 G2 B 0
I am using below procedure for getting desired output
CREATE DEFINER=`root`#`localhost` PROCEDURE `stmt`()
BEGIN
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(goals = ''',
goals,
''', round(value, 2), NULL)) AS ',
goals
)
) INTO #sql
FROM sgwebdb.dim_module;
SET #sql = CONCAT('SELECT alternative, ', #sql, ' FROM sgwebdb.dim_module GROUP BY alternative');
prepare stmt from #sql;
But if Dim_Module don't have any row then procedure is not take care and I am getting error.
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
Please help to take care of empty table.
Maybe because #sql is null.
Try setting it to some value with IFNULL
SET #sql = CONCAT('SELECT alternative, ', IFNULL(#sql,'somecolumnor*here'), ' FROM sgwebdb.dim_module GROUP BY alternative');
Or detect that #sql is null and do something else.
You may check #sql before using it within your second SELECT:
IF #sql
THEN
SET #sql = CONCAT('SELECT alternative, ', #sql, ' FROM sgwebdb.dim_module GROUP BY alternative');
prepare stmt from #sql;
END IF;