i have 3 tables like this
create table order_match
(
id int(10) PRIMARY KEY not null,
order_status_id int(10) not null
);
create table order_match_detail
(
id int(10) PRIMARY KEY not null,
order_match_id int(10) not null,
product_id int(10) NOT NULL
);
create table product
(
id int(10) PRIMARY KEY not null,
name varchar(255) not null
);
Insert into order_match (id, order_status_id)
select 1, 6 union all
select 2, 7 union all
select 3, 6 union all
select 4, 6;
Insert into order_match_detail (id, order_match_id, product_id)
select 1, 1, 147 union all
select 2, 2, 148 union all
select 3, 3, 147 union all
select 4, 4, 149 union all
select 5, 4, 147;
Insert into product (id, name)
select 147, 'orange' union all
select 148, 'carrot' union all
select 149, 'Apple';
with order_match.id = order_match_detail.order_match_id
and order_match_detail.product_id = product.id
i want to make the data where order_status_id not in 7 then it's success transaction and from that success transaction, if the transaction buy apple, then the column of apple contain 1 else if not buying, then 0 and this is my expected results, i want to make this data to analyze in
id (in order_match) | Orange | Carrot | Apple
1 1 0 0
3 1 0 0
4 1 0 1
with that problem i can solve it with this query
select om.id,
count(DISTINCT case when omd.product_id = 147 THEN 1 END) Orange,
count(DISTINCT case when omd.product_id = 148 THEN 1 END) Carrot,
count(DISTINCT case when omd.product_id = 149 THEN 1 END) Apple
from order_match om
left join order_match_detail omd
on om.id = omd.order_match_id
where om.order_status_id in (4, 5, 6, 8)
group by om.id
the real problem is, in my real database, it's contain 1550 product_id, how to make it automatically so no need to input manual the product_id untill 1550 product_id
this is the fiddle https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=c0eb7fe1b012ab1c909d37e325a8d434
i've tried the new queries like this and it still wrong
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when product.name = ''',
product.name,
''' then 1 end) AS ',
replace(product.name, ' ', '')
)
) INTO #sql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product p
on omd.product_id = p.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
your query is almost correct you were missing on alias instead of p you should use 'product' in second query, it would work
SET group_concat_max_len = 1000000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when product.name = ''',
product.name,
''' then 1 end) AS ',
'"',replace(product.name, ' ', ''),'"'
)
) INTO #sql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id as id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product product
on omd.product_id = product.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
You can remove DISTINCT from GROUP_CONCAT(DISTINCT if you are sure that product id's is having unique names for each id's
Then i would get the exact result as you mentioned in question else just you will see, Apple column first and Orange column last, overall result is as expected.
Related
school_name
class
medium
total
srk
1
english
13
srk
2
english
14
srk
3
english
15
srk
1
french
16
srk
2
french
16
srk
3
french
18
vrk
1
english
17
vrk
1
french
18
I want that output by
school_name
class1eng
class1french
class2eng
class2french
class3english
class3french
[output needed][ otput required
output
You’re looking for multiple select statements along with appropriate cases to satisfy.
This should work for you
Select
school_name,
Sum(Case when (class=1 and medium=‘English’) then total else 0 end) as class1english,
Sum(Case when (class=1 and medium=‘French’) then total else 0 end) as class1french,
Sum(Case when (class=2 and medium=‘English’) then total else 0 end) as class2english,
Sum(Case when (class=2 and medium=‘French’) then total else 0 end) as class2french,
Sum(Case when (class=3 and medium=‘English’) then total else 0 end) as class3english,
Sum(Case when (class=3 and medium=‘French’) then total else 0 end) as class3french
From
table_name
Group by
school_name
Seems to be a simple ask, assumed you also want to order your results. Please check below query if that helps
SELECT school_name, class, medium, SUM(total) AS Total
FROM <Table Name>
GROUP BY school_name, class, medium
This solution is for general purpose, complex, but functional.
I've made it for myself as exercise and challenge.
/* --------------- TABLE --------------- */
CREATE TABLE schools_tab
(school VARCHAR(9), class INT, subj VARCHAR(9), total INT);
INSERT INTO schools_tab VALUES
('srk', 1, 'english', 13),
('srk', 2, 'english', 14),
('srk', 3, 'english', 15),
('srk', 1, 'french', 16),
('srk', 2, 'french', 16),
('srk', 3, 'french', 18),
('vrk', 1, 'english', 17),
('vrk', 1, 'french', 18);
/* -------------- DYNAMIC QUERY --------------- */
SET #sql=NULL;
WITH cte AS (
SELECT school, class, subj, ROW_NUMBER() OVER (PARTITION BY school) AS idx, DENSE_RANK() OVER (ORDER BY school) AS ids
FROM (SELECT DISTINCT school FROM schools_tab) A LEFT JOIN (SELECT DISTINCT class, subj FROM schools_tab) B ON (1=1)
), cte2 AS (
SELECT A.ids, A.idx, A.school, A.class, A.subj, COALESCE(B.total, 0) AS total
FROM cte A LEFT JOIN schools_tab B ON (A.school=B.school AND A.class=B.class AND A.subj=B.subj)
), cte3 AS (
SELECT DISTINCT class, subj
FROM schools_tab
ORDER BY class, subject
)
SELECT CONCAT('WITH RECURSIVE cte AS (
SELECT school, class, subj, ROW_NUMBER() OVER (PARTITION BY school) AS idx, DENSE_RANK() OVER (ORDER BY school) AS ids
FROM (SELECT DISTINCT school FROM schools_tab) A LEFT JOIN (SELECT DISTINCT class, subj FROM schools_tab) B ON (1=1)
), cte2 AS (
SELECT A.ids, A.idx, A.school, A.class, A.subj, COALESCE(B.total, 0) AS total
FROM cte A LEFT JOIN schools_tab B ON (A.school=B.school AND A.class=B.class AND A.subj=B.subj)
), ctx AS ('
'SELECT (SELECT MAX(ids) FROM cte2) AS n,',
GROUP_CONCAT(DISTINCT CONCAT( '(SELECT total FROM cte2 WHERE idx=',idx,' AND ids=n) AS class',class,subj ) ORDER BY class, subj),
' UNION ALL SELECT n-1 AS n,',
GROUP_CONCAT(DISTINCT CONCAT( '(SELECT total FROM cte2 WHERE idx=',idx,' AND ids=n) AS class',class,subj ) ORDER BY class, subj),
' FROM ctx WHERE n>0',
') SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(''srk,vrk'', '','', n+1), '','', -1) AS school,',
GROUP_CONCAT(DISTINCT CONCAT('class',class,subj)),
' FROM ctx ORDER BY school'
) INTO #sql
FROM cte2;
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
i have 3 tables like this
create table order_match
(
id int(10) PRIMARY KEY not null,
order_status_id int(10) not null
);
create table order_match_detail
(
id int(10) PRIMARY KEY not null,
order_match_id int(10) not null,
product_id int(10) NOT NULL
);
create table product
(
id int(10) PRIMARY KEY not null,
name varchar(255) not null
);
Insert into order_match (id, order_status_id)
select 1, 6 union all
select 2, 7 union all
select 3, 6 union all
select 4, 6;
Insert into order_match_detail (id, order_match_id, product_id)
select 1, 1, 147 union all
select 2, 2, 148 union all
select 3, 3, 147 union all
select 4, 4, 149 union all
select 5, 4, 147;
Insert into product (id, name)
select 147, 'orange' union all
select 148, 'carrot' union all
select 149, 'Apple';
with order_match.id = order_match_detail.order_match_id
and order_match_detail.product_id = product.id
i want to make the data where order_status_id not in 7 then it's success transaction and from that success transaction, if the transaction buy apple, then the column of apple contain 1 else if not buying, then 0 and this is my expected results, i want to make this data to analyze in
id (in order_match) | Orange | Carrot | Apple
1 1 0 0
3 1 0 0
4 1 0 1
the real problem is i've just fit in whether the version of mysql, and fit in with the same data type for every table, i dont really know why in my fiddle it's work, but on mysql it's contain
error code :1064.you have an error in your sql syntax near ' '' at
line 1
this is my Fiddle
new UPDATE
after take a look with the data, i assume the product name in field have format that cant be acceted mysql. so i've made the new query like this
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when name = ''',
name,
''' then 1 end) AS ',
concat('product', id)
)
) INTO #sql
from product;
SET #sql1 = CONCAT('SELECT omd.order_match_id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product p
on omd.product_id = p.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
This is the new fiddle
but in my new mysql it's said
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 'from order_match_detail omd left join order_match
om on omd.order_match_id = o' at line 1
this was almost same cases in this case MySQL pivot row into dynamic number of columns but the results was different and it make me confuse.
let's say i have 3 tables
create table order_match
(
id int(10) PRIMARY KEY not null,
order_status_id int(10) not null
);
create table order_match_detail
(
id int(10) PRIMARY KEY not null,
order_match_id int(10) not null,
product_id int(10) NOT NULL
);
create table product
(
id int(10) PRIMARY KEY not null,
name varchar(255) not null
);
Insert into order_match (id, order_status_id)
select 1, 6 union all
select 2, 7 union all
select 3, 6 union all
select 4, 6;
Insert into order_match_detail (id, order_match_id, product_id)
select 1, 1, 147 union all
select 2, 2, 148 union all
select 3, 3, 147 union all
select 4, 4, 149 union all
select 5, 4, 147;
Insert into product (id, name)
select 147, 'orange' union all
select 148, 'carrot' union all
select 149, 'Apple';
with order_match.id = order_match_detail.order_match_id
and order_match_detail.product_id = product.id
so like the previous case in MySQL pivot row into dynamic number of columns i want to input the product name with the transaction in order_status_id not in 7 (because 7 is expired transaction and denied)
the expected results was like this :
id (in order_match) | Orange | Carrot | Apple
1 1 0 0
3 1 0 0
4 1 0 1
based on solution in previous cases, i used this
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when product.name = ''',
product.name,
''' then 1 end) AS ',
replace(product.name, ' ', '')
)
) INTO #sql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product p
on omd.product_id = p.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
but idk why return 0 and it's no way
this is the fiddle https://www.db-fiddle.com/f/nDe3oQ3VdtfS5QDokieHN4/6
For your GROUP_CONCAT query; in your case stmt, you are referring to your product table as product itself. But in your join query, you are referring to product table as alias p. Since the first group_concat query is a part of the join query, you need to keep the table aliases same.(made changes at line 5)
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when p.name = ''',
product.name,
''' then 1 end) AS ',
replace(product.name, ' ', '')
)
) INTO #pivotsql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id, ', #pivotsql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product p
on omd.product_id = p.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
I have table user_completed
CREATE TABLE IF NOT EXISTS `user_completed` (
`rowId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`designer_id` int(10) unsigned NOT NULL,
`status` varchar(54) DEFAULT NULL,
PRIMARY KEY (`rowId`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
INSERT INTO `user_completed` (`rowId`, `designer_id`, `status`) VALUES
(1, 1, accept),
(2, 1, reject),
(3, 1, accept),
(4, 1, reject),
(5, 1, overtime),
(6, 2, accept)
(7, 2, accept)
(8, 3, accept)
(9, 2, reject);
Which look like:
rowId designer_id status
1 1 accept
2 1 reject
3 1 accept
4 1 reject
5 1 overtime
6 2 accept
7 2 accept
8 3 accept
9 2 reject
I want to get result below:
designer_id accept overtime reject
1 2 1 2
2 2 0 1
3 1 0 0
But I have no idea how to group designer_id then count distinct status and each into columns like above.
Try this
SELECT designer_id,
SUM(IF(status = 'accept',1,0)) as 'Accept',
SUM(IF(status = 'reject',1,0)) as 'Reject',
SUM(IF(status = 'overtime',1,0)) as 'Overtime'
FROM
user_completed
Group By designer_id
Fiddle Demo
As Jack said It's simply workig with this
SELECT designer_id,
SUM(status = 'accept') as 'Accept',
SUM(status = 'reject') as 'Reject',
SUM(status = 'overtime') as 'Overtime'
FROM
user_completed
Group By designer_id
Fiddle Demo
Try this one it wil work
select designer_id,
count(case status when 'accept'then 1 else null end)as accept,
count(case status when 'reject'then 1 else null end)as reject,
count(case status when 'overtime'then 1 else null end)as overtime
from user_completed group by designer_id
If you don't know how many distinct status you have then you can check this link for solution
Mysql query to dynamically convert rows to columns
e.g you can use something like below
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(IF(`status` = "', `status`, '",1,0)) AS ', `status`)
) INTO #sql
FROM user_completed;
SET #sql = CONCAT('SELECT designer_id, ', #sql, '
FROM user_completed
GROUP BY designer_id');
SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I have data in database with three columns id, topic, and subtopic. Something like this,
CREATE TABLE Table2 (`id` int, `topic` varchar(5), `subtopic` varchar(6));
INSERT INTO Table2 (`id`, `topic`, `subtopic`) VALUES
(1, 'place', 'paris'),
(1, 'group', 'A'),
(1, 'group', 'B'),
(2, 'place', 'us'),
(2, 'group', 'C'),
(3, 'group', 'A'),
(3, 'water', 'salt'),
(4, 'water', 'sweet'),
(4, 'world', 'ep'),
(5, 'place', 'venus'),
(5, 'place', 'paris'),
(5, 'group', 'A');
I want to output the result matrix place vs group from topic. Something like this.
Paris|US|Venus
A 2 |0 | 1
B 1 |0 | 0
C 0 |1 | 0
Idea is to pick up all the values of 'Group' (A,B,C) and 'Places' (paris,us,venus) in subtopic column. And then find number of co-occurrences with such condition.
Any idea how to solve in MySql?
You will need to join on your table twice to get the group and places, then you can use an aggregate function with a CASE expression to convert the rows into columns:
select g.subtopic as `group`,
sum(case when p.subtopic = 'Paris' then 1 else 0 end) Paris,
sum(case when p.subtopic = 'US' then 1 else 0 end) US,
sum(case when p.subtopic = 'Venus' then 1 else 0 end) Venus
from table2 g
left join table2 p
on g.id = p.id
and p.topic = 'place'
where g.topic = 'group'
group by g.subtopic;
See SQL Fiddle with Demo.
If you are going to have unknown values for the subtopic, then you can use a prepared statement and dynamic SQL:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'sum(case when p.subtopic = ''',
subtopic,
''' then 1 else 0 end) as `',
subtopic, '`')
) INTO #sql
FROM table2
where topic = 'place';
SET #sql = CONCAT('SELECT g.subtopic as `group`, ', #sql, '
from table2 g
left join table2 p
on g.id = p.id
and p.topic = ''place''
where g.topic = ''group''
group by g.subtopic');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo