MySQL pivot row to column dynamically - mysql

i have table:day
id | jour
1 Lundi 01 Août 2016
2 Mardi 02 Août 2016
3 Mercredi 03 Août 2016
4 Jeudi 04 Août 2016
there will be 50 rows i want output like:
Lundi 01 Août 2016 Mardi 02 Août 2016 Mercredi 03 Août 2016
1 2 3

you can do it easy with this queries: first generate the query and then execute it as prepared statement.
SET SESSION group_concat_max_len = 1000000;
SELECT
CONCAT('SELECT ',
GROUP_CONCAT(
CONCAT (
"MAX(IF(`jour` = '",jour,'\',id,NULL)) AS `',jour,'`'
)
),
' FROM `day`'
) INTO #SQL
FROM
( SELECT *
FROM `day`
ORDER BY id
LIMIT 1,2
) AS data;
select #SQL; -- see the query only for debug
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
sample
MariaDB [yourSchema]> select * from day;
+----+------------------------+
| id | jour |
+----+------------------------+
| 1 | Lundi 01 Août 2016 |
| 2 | Mardi 02 Août 2016 |
| 3 | Mercredi 03 Août 2016 |
| 4 | Jeudi 04 Août 2016 |
+----+------------------------+
4 rows in set (0.00 sec)
MariaDB [yourSchema]> SELECT
-> CONCAT('SELECT ',
-> GROUP_CONCAT(
-> CONCAT (
-> "MAX(IF(`jour` = '",jour,'\',id,NULL)) AS `',jour,'`'
-> )
-> ),
-> ' FROM `day`'
-> ) INTO #SQL
-> FROM `day`;
Query OK, 1 row affected (0.00 sec)
MariaDB [yourSchema]> PREPARE stmt FROM #SQL;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
MariaDB [yourSchema]> EXECUTE stmt;
+---------------------+---------------------+------------------------+---------------------+
| Lundi 01 Août 2016 | Mardi 02 Août 2016 | Mercredi 03 Août 2016 | Jeudi 04 Août 2016 |
+---------------------+---------------------+------------------------+---------------------+
| 1 | 2 | 3 | 4 |
+---------------------+---------------------+------------------------+---------------------+
1 row in set (0.00 sec)
MariaDB [yourSchema]> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
MariaDB [yourSchema]>

Related

How to count rows by date in mysql and show dynamic headers

I need to show count of each sources(type colum) and show according to date range
Currently my data is as following
id type date
11 air 2019-10-21 10:00:01
21 air 2019-10-21 10:00:02
31 air 2019-10-21 10:01:03
41 air 2019-10-21 11:01:03
51 air 2019-10-21 12:01:03
61 water 2019-10-21 12:01:03
71 water 2019-10-21 15:01:04
81 water 2019-10-22 16:01:03
81 sea 2019-10-22 16:01:03
81 sea 2019-10-24 16:01:03
I want to achive output like the following
type 2019-10-21 | 2019-10-22
air 5 0
water 2 1
sea 0 1
and also give range in between 2019-10-21 and 2019-10-21
i have tried this query
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when type = ',
'type',
' then type else null end) AS ''',
date(date), ''''
)
) INTO #sql
FROM content where date(`date`) between '2021-02-08' AND '2021-02-10';
SET #sql = CONCAT('SELECT type, ', #sql, '
FROM content
GROUP BY type limit 2');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
but it give wrong results and counts the total
type 2021-02-08 2021-02-09 2021-02-10
sea 3 3 3
air 5316 5316 5316

mySQL creating a complex query/ view/ report

I have 3 tables as below :
1/ Table 'order_fruit'
-------------------------------------------------------------
id_fruit_table | fruit_name | order_quantity | delivery_date
---------------+------------+----------------+---------------
1 |mango | 10 | 04 2018
2 |mango | 5 | 05 2018
3 |banana | 20 | 04 2018
4 |pineapple | 9 | 06 2018
2/ Table 'stock_fruit'
---------------------------------------------------
id_stock | fruit_name_stock | stock_quantity
--------------+-------------------+----------------
1 | mango | 5
2 | pineapple | 10
3/ Table 'pipeline'
--------------------------------------------------------------------
id_pipeline | fruit_pipeline | receive_date | pipeline_quantity
--------------+------------------+--------------+-------------------
1 | mango | 04 2018 | 5
2. | banana | 05 2018 | 15
How can i make a query/ view/ report like below:
-----------------------------------------------------------------------------------
fruit | 04 2018 | 05 2018 | 06 2018
---------+---------------------------------------------------------------+---------
| order_qty-| stock-| pipeline | order_qty- | stock- | pipeline | ...
---------+-----------+-------+----------+------------+--------+----------+---------
mango | 10 | 5 | 5 | 5 | 0 | 0 | ...
banana | 20 | 0 | 0 | 0 | 0 | 15 | ...
pineapple| 0 | 10 | 0 | 0 | 10 | 0 | ...
Here opening stock for 05 2018 = 04 2018(stock + pipeline - order_qty)
Opening stock for 06 2018 = 05 2018(stock + pipeline - order_qty)
Try to use the following way
-- the first query returns all distinct dates
SELECT delivery_date oper_date
FROM order_fruit
UNION
SELECT receive_date
FROM pipeline
And you can use this information to generate the second query
-- the second query is generated using information about dates from the first query
SELECT
fruit_name
,SUM(stock_quantity) stock_quantity
-- 04 2018
,SUM(CASE WHEN oper_date='04 2018' THEN order_quantity END) order_quantity_04_2018
,SUM(CASE WHEN oper_date='04 2018' THEN pipeline_quantity END) pipeline_quantity_04_2018
-- 05 2018
,SUM(CASE WHEN oper_date='05 2018' THEN order_quantity END) order_quantity_05_2018
,SUM(CASE WHEN oper_date='05 2018' THEN pipeline_quantity END) pipeline_quantity_05_2018
-- 06 2018
,SUM(CASE WHEN oper_date='06 2018' THEN order_quantity END) order_quantity_06_2018
,SUM(CASE WHEN oper_date='06 2018' THEN pipeline_quantity END) pipeline_quantity_06_2018
-- ...
FROM
(
SELECT delivery_date oper_date,fruit_name,order_quantity,NULL stock_quantity,NULL pipeline_quantity
FROM order_fruit
UNION ALL
SELECT NULL,fruit_name_stock,NULL,stock_quantity,NULL
FROM stock_fruit
UNION ALL
SELECT receive_date,fruit_pipeline,NULL,NULL,pipeline_quantity
FROM pipeline
) q
GROUP BY fruit_name
SQL Fiddle - http://www.sqlfiddle.com/#!9/ceb1680/2

Calculating cumulative values for every 12 months on tables with possibly null values

I have this table:
Month Year MV MI fullDate
-----------------------------------------------------------------
...
5 2015 1 5 2015-05-01
6 2015 1 10 2015-06-01
7 2015 3 10 2015-07-01
8 2015 2 10 2015-08-01
11 2015 1 10 2015-11-01
1 2016 4 10 2016-01-01
6 2016 1 20 2016-06-01
7 2016 null 10 2016-07-01
8 2016 2 5 2016-08-01
...
I need to create another table with cumulative values:
Month Year AMV AMI
-----------------------------------------------------------------
...
7 2015 3 10
8 2015 5 20
11 2015 6 30
1 2016 10 40
6 2016 11 60
7 2016 0 10
8 2016 2 15
...
The cumulative calculations must start on a July and end on June of the next year. In this example, the cumulative fields started "accumulating" from July, 2015 and ended on June, 2016. These calculations re-started on July, 2016 getting another cycle for cumulative values to "calculate"
I made a similar question before but I just found out this "periodicity" for calculations of cumulative. One more thing... some values on the first table could be null and need to be considered as 0.
Please, tell me how can this be done?
I have modified the quer from #Sebastian. The init is also in the query. the counter will reset each year and the where is not necessary
SELECT
(#amv:=IF(MONTH(fulldate)=7,MV, IF(ISNULL(MV), 0, #amv+MV))) AS AMV,
(#ami:=IF(MONTH(fulldate)=7,MI, IF(ISNULL(MI), 0, #ami+MI))) AS AMI,
fullDate
FROM
input
CROSS JOIN ( SELECT #amv := 0, #ami := 0) AS init
ORDER BY fullDate ASC;
sample
mysql> select * from input;
+----+------+------+------------+
| id | MV | MI | fullDate |
+----+------+------+------------+
| 1 | 1 | 10 | 2015-08-01 |
| 2 | 2 | 20 | 2015-09-01 |
| 3 | 3 | 30 | 2015-07-01 |
| 4 | 8 | 33 | 2016-07-01 |
| 5 | 2 | 8 | 2016-08-01 |
+----+------+------+------------+
5 rows in set (0,00 sec)
mysql> SELECT
-> (#amv:=IF(MONTH(fulldate)=7,MV, IF(ISNULL(MV), 0, #amv+MV))) AS AMV,
-> (#ami:=IF(MONTH(fulldate)=7,MI, IF(ISNULL(MI), 0, #ami+MI))) AS AMI,
-> fullDate
-> FROM
-> input
-> CROSS JOIN ( SELECT #amv := 0, #ami := 0) AS init
-> ORDER BY fullDate ASC;
+------+------+------------+
| AMV | AMI | fullDate |
+------+------+------------+
| 3 | 30 | 2015-07-01 |
| 4 | 40 | 2015-08-01 |
| 6 | 60 | 2015-09-01 |
| 8 | 33 | 2016-07-01 |
| 10 | 41 | 2016-08-01 |
+------+------+------------+
5 rows in set (0,00 sec)
mysql>
This does the trick:
SET #amv := 0, #ami := 0;
SELECT
(#amv:=IF(ISNULL(MV), 0, #amv+MV)) as AMV,
(#ami:=IF(ISNULL(MI), 0, #ami+MI)) as AMI,
fullDate
FROM
input
WHERE
fullDate >= "2015-07-01" AND
fullDate < "2016-07-01"
ORDER BY fullDate ASC;

Tables with dynamic names as fields

I have a table which contains a field that when we add a letter to it it becomes a table name, so far i can only fetch all from the first table and then do each table_name at once. So i'm looking for a way to all of the above in one query.
Queries
select table_name from main
select date,data from X$table_name order by date desc limit 1
main
table_name name
000001 X1
000002 X2
000003 X3
000004 X4
000005 X5
Table X000001
id date data
5 2016-12-05 data_02_05
4 2016-12-04 data_02_04
3 2016-12-03 data_02_03
2 2016-12-02 data_02_02
1 2016-12-01 data_02_01
Table X000002
id date data
5 2016-12-05 data_02_05
4 2016-12-04 data_02_04
3 2016-12-03 data_02_03
2 2016-12-02 data_02_02
1 2016-12-01 data_02_01
Expected result
table_name date data
000001 2016-12-05 data_01_05
000002 2016-12-05 data_02_05
000003 2016-12-05 data_03_05
000004 2016-12-05 data_04_05
000005 2016-12-05 data_05_05
you need to use a dynamic query or prepared statement for that purpose.
declare #tab_name varchar(100);
set #tab_name := (select table_name from main);
SET #t1 := CONCAT("select `date`,data from X",#tab_name," order by `date` desc limit 1");
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;

Order by month giving reverse order in Mysql

I'm trying to order a mysql query according to the month name but it is ordering in reverse order .I have tried both the ASC and DESC order but not working!This is what i'm getting :
order_amount month_number
370.245 Dec
0.01 Aug
0.02 July
0.01 May
2 Apr
3 Mar
4 Feb
5 Jan
This is the query:
select sum(amnt) as order_amount,month_number from orders where paid =1 GROUP BY month_number ORDER BY MONTH(month_number) ASC
This is a sample table 'order' on which i'm running query
order_amount month_number paid
370.245 Jan 1
0.01 Aug 1
0.02 July 1
0.01 Apr 1
2 May 0
3 Mar 1
4 Feb 0
5 Nov 0
month_number() is a lousy name for a string name for the month. That said, your attempts will not work, because month() takes a date, not a string representation. The best way is probably just to use case:
order by (case when month_number = 'Jan' then 1
when month_number = 'Feb' then 2
. . .
when month_number = 'Dec' then 12
end)
I would strongly suggest you include a date or actual month number in the table. And, rename month_number to something like month_name.
According to your sample, you've got 'Dec', 'Aug' and so on in your month_number field.
How is month(month_number) supposed to work if you don't pass a valid date type? if you pass some random text you'll just get NULL and can't order by NULL
http://sqlfiddle.com/#!2/3a774d/3/0
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_month
SELECT * FROM my_table;
+-------+
| month |
+-------+
| Apr |
| Aug |
| Dec |
| Feb |
| Jan |
| Jul |
| Jun |
| Mar |
| May |
| Nov |
| Oct |
| Sep |
+-------+
SELECT * FROM my_table ORDER BY STR_TO_DATE(CONCAT('2014-',month,'-01'),'%Y-%b-%d');
+-------+
| month |
+-------+
| Jan |
| Feb |
| Mar |
| Apr |
| May |
| Jun |
| Jul |
| Aug |
| Sep |
| Oct |
| Nov |
| Dec |
+-------+
... or something like that