I have a table structure as follows:
Shops Table:
id | shop_name |
---|---|
1 | My Shop |
2 | Another Shop |
3 | Final Shop |
Orders Table:
shop_id | order_id | data | created_at |
---|---|---|---|
1 | 123 | json | 01/01/2023 |
2 | 456 | json | 01/01/2023 |
3 | 234 | json | 02/02/2023 |
1 | 765 | json | 03/02/2023 |
2 | 435 | json | 04/03/2023 |
3 | 788 | json | 04/03/2023 |
From these 2 tables, I would like to select the shops name, ID and the count of its orders grouped by the month they were created, something like:
shop_id | shop_name | order_count_january_23 | order_count_february_23 | etc |
---|---|---|---|---|
1 | My Shop | 1 | 2 | … |
2 | Another Shop | 12 | 45 | … |
3 | Final Shop | 8 | 36 | … |
I have tried grouping the number of orders but i can’t seem to be able to get the exact output I need, I’ve also tried using sub-queries but to no avail.
SELECT orders.id,
shops.name,
count(orders.id) as 'Orders',
MONTH(orders.created_at) as Month,
YEAR(orders.created_at) as Year
FROM orders
JOIN shops on shops.id = orders.id
GROUP BY orders.wholesaler_id, Year, Month
I know the above does not work however this is where I became stumped. It does however, give me a list of shops with there order numbers but this is not in the correct format
Any help is massivley appreciated.
FOR MYSQL
SET SESSION group_concat_max_len = 1000000;
SET @columns = NULL;
SELECT GROUP_CONCAT(
DISTINCT CONCAT(
'SUM(CASE WHEN MONTH = ', MONTH,
' AND YEAR = ', YEAR,
' THEN 1 ELSE 0 END) AS order_count_',
MONTHNAME, '_', YEAR
)
SEPARATOR ', '
) INTO @columns
FROM (
SELECT DISTINCT MONTH(created_at) AS MONTH, YEAR(created_at) AS YEAR,
MONTHNAME(created_at) AS MONTHNAME
FROM Orders
) AS months;
SET @sql = CONCAT('SELECT
s.ID AS shop_id,
s.shop_name,
', @columns, '
FROM
shops s
LEFT JOIN (
SELECT shop_id,
MONTH(created_at) AS MONTH,
YEAR(created_at) AS YEAR
FROM orders
GROUP BY shop_id, MONTH(created_at), YEAR(created_at)
) o ON s.ID = o.shop_id
GROUP BY
s.ID, s.shop_name');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
FOR MSSQL
DECLARE @columns NVARCHAR(MAX);
DECLARE @sql NVARCHAR(MAX);
-- Generate a comma-separated list of aggregated expressions for each month and year
SELECT @columns = COALESCE(@columns + ', ', '') +
'SUM(CASE WHEN MONTH = ' + CONVERT(NVARCHAR(2), MONTH) +
' AND YEAR = ' + CONVERT(NVARCHAR(4), YEAR) +
' THEN 1 ELSE 0 END) AS order_count_' + MONTHNAME + '_' + CONVERT(NVARCHAR(4), YEAR)
FROM (
SELECT DISTINCt MONTH(created_at) AS MONTH, YEAR(created_at) AS YEAR, FORMAT(created_at, 'MMMM') AS MONTHNAME
FROM Orders
) AS months;
-- Construct the dynamic SQL query
SET @sql = CONCAT('SELECT
s.id AS shop_id,
s.shop_name,
', @columns, '
FROM
Shops s
LEFT JOIN (
SELECT shop_id,
MONTH(created_at) AS MONTH,
YEAR(created_at) AS YEAR
FROM Orders
GROUP BY shop_id, MONTH(created_at), YEAR(created_at)
) o ON s.id = o.shop_id
GROUP BY
s.id, s.shop_name');
-- Execute the dynamic SQL query
EXEC sp_executesql @sql;
Try using COUNT
with IF
, like so:
SELECT
orders.order_id,
shops.shop_name,
COUNT(IF(
MONTH(orders.created_at) = 1 AND YEAR(orders.created_at) = 2023,
1,
NULL
)) AS order_count_january_23,
FROM orders
JOIN shops ON shops.id = orders.id
GROUP BY orders.order_id, shops.shop_name
The result should only be for the current or previous year or for the last 6 / 12 months. Or for all entries in the table
For all entries in the table is what i am looking for
If there are records for 90 different months, do you want 90 columns?
Thats correct, I have a lot of data in the tables
Does this help?
Show 3 more comments