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

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;

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.

MySQL LIMT is a subquery?

I want to use a select statement to control the limit of another select query, I cant get it to work, what I have below. The Select in the braces returns an INT.
Im newer to MySQL so im not sure what I should use instead to get this to work.
SELECT *
FROM `tbl_prod`
WHERE prod_id = 32
ORDER BY prod_level ASC , prod_date
LIMIT
(SELECT max_count
FROM Prod_subscription
WHERE prod_id = 32)
You can't write subquery in LIMIT, but you can use dynamic SQL to make your expected result.
SET #num = (
SELECT max_count
FROM Prod_subscription
WHERE prod_id = 32);
PREPARE STMT FROM 'SELECT *
FROM `tbl_prod`
WHERE prod_id = 32
ORDER BY prod_level ASC , prod_date
LIMIT ?';
EXECUTE STMT USING #num;

What is the workaround if group_concat doesn't return a value

I have written a query which transforms a couple of rows based on a condition into columns.
However, there are cases where no row meets the condition but I want to return some results.
Below is a sample of the table and the results I am looking for.
Source table:
id
respondent_id
demographic
question
answer
1
1
checked
Age
30
2
1
null
education
masters
3
1
checked
height
1.8m
4
1
null
income
$1
5
1
null
address
ISS
6
1
null
talent
dancing
7
2
checked
Age
20
8
2
null
education
high school
9
2
checked
height
4m
10
2
null
income
$3.2
11
2
null
address
High sea
12
2
null
talent
singing
Sample results after transformation:
id
respondent_id
Age
height
question
answer
2
1
30
1.8m
education
masters
4
1
30
1.8m
income
$1
5
1
30
1.8m
address
ISS
6
1
30
1.8m
talent
dancing
8
2
20
4m
education
high school
10
2
20
4m
income
$3.2
11
2
20
4m
address
High sea
12
2
20
4m
talent
singing
Current MySQL statement:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'(SELECT l.answer FROM source_table l where l.respondent_id = a.respondent_id AND l.question = ', b.question,')
AS ',b.question
)
) INTO #sql
FROM source_table b
WHERE b.demographic IS NOT NULL;
SET #sql =
CONCAT('SELECT respondents_id,
',#sql,',
a.question , a.answer
FROM source_table a
WHERE a.demographic IS NULL
GROUP BY id
');
PREPARE stmt FROM #sql;
EXECUTE stmt;
To clarify, the above query works when there are rows that are "checked" for the demographic column, however when there are no "checked" cells, the whole query fails.
So I would like a query that works under all conditions, whether there are demographic rows or not.
If there are no demographic rows, the query is supposed to return the data without the new columns
I'm a little confused on why you are using dynamic SQL. Window functions seems to do what you want:
select t.*
from (select t.*,
max(case when question = 'Age' then answer end) over (partition by respondent_id ) as age,
max(case when question = 'height' then answer end) over (partition by respondent_id ) as height
from source_table st
) t
where demographic is null;
I suppose you could use this as a template if you don't know the "checked" columns.
I think your goal is to generate a query like this:
SELECT respondent_id, a.question , a.answer,
(SELECT l.answer
FROM source_table l
WHERE l.respondent_id = a.respondent_id AND l.question = "Age") AS Age,
(SELECT l.answer
FROM source_table l
WHERE l.respondent_id = a.respondent_id AND l.question = "height") AS height
FROM source_table a
WHERE a.demographic IS NULL
GROUP BY respondent_id, a.question , a.answer;
However, your current syntax is generating a query like this:
SELECT respondents_id,
SELECT l.answer FROM source_table l where l.respondent_id = a.respondent_id
AND l.question = Age AS Age,
SELECT l.answer FROM source_table l where l.respondent_id = a.respondent_id
AND l.question = height AS height,
a.question , a.answer
FROM source_table a
WHERE a.demographic IS NULL
GROUP BY id;
There are no parentheses () wrapped around the SELECT .. correlated subqueries which will return the following error
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 'SELECT l.answer FROM source_table l where l.respondent_id = a.respondent_id AND ' at line 2
You need to modify your syntax as following:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'(SELECT l.answer
FROM source_table l where l.respondent_id = a.respondent_id
AND l.question = "', b.question,'") AS ',b.question)
) INTO #sql
FROM source_table b
WHERE b.demographic IS NOT NULL;
SELECT #sql; /*added in between to check the current variable value. Removable.*/
SET #sql =
CONCAT('SELECT respondent_id, a.question , a.answer,
',#sql,'
FROM source_table a
WHERE a.demographic IS NULL
GROUP BY respondent_id, a.question , a.answer
');
SELECT #sql; /*added in between to check the current variable value. Removable.*/
PREPARE stmt FROM #sql;
EXECUTE stmt;
Demo fiddle
#FaNo_FN #ysth
I managed to fix it using the fiddle you had posted and your comments.
I added the following code between the 2 queries to check if the variable is set.
SET #sql := IF(#sql IS NULL,'',#sql);
I also added a second CONCAT() before the GROUP_CONCAT to add a ',' separator.
This is the link to the fiddle
I would make your GROUP_CONCAT have SEPARATOR '' and start your first CONCAT( args with a ',', and remove the comma after SELECT respondents_id. But some of your other syntax doesn't look right from just visual inspection.

Mysql Pivot some column in 1 table [duplicate]

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:

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.