How to pivot in mysql for previous date in mysql - mysql

The table structure and data is present at https://www.db-fiddle.com/f/5rKXiavsoMeQazSHwxaTVK/0
i am trying to get the percentage of all previous date range.
circle_name`|current_capacity|2020-03-16|2020-03-17|2020-03-18|
where current capacity is the max date capacity and the percentage of each date in rows.
The final out like https://www.db-fiddle.com/f/wTFejVRzQBTXZkfWjBuqq8/0
select circle_name,Subscriber as current_capacity,
Subscriber/Subs_Capacity * 100 as percentage,
DATE_FORMAT(date,'%y-%m-%d') as date
from circle
where date BETWEEN date_add('2020-03-18',interval -3 day)
and '2020-03-18'
Please help here in pivot in mysql.

Here is one approach that uses conditional aggregation. Instead of assigning actual dates to column names (which would require dynamic SQL), this works by setting a variable that represents the date from which you want the computation to start, and then generates columns named d_2 (for day - 2), d_1 and d_0.
set #mydate = '2020-03-18';
select
circle_name,
max(case when date = #mydate then subscriber end) current_capacity,
100 * sum(case when date = #mydate - interval 2 day then subscriber end)
/ sum(case when date = #mydate - interval 2 day then subs_capacity end) d_2,
100 * sum(case when date = #mydate - interval 1 day then subscriber end)
/ sum(case when date = #mydate - interval 1 day then subs_capacity end) d_1,
100 * sum(case when date = #mydate then subscriber end)
/ sum(case when date = #mydate then subs_capacity end) d_0
from circle
group by circle_name;
In your db fiddle, the query yields:
| circle_name | current_capacity | d_2 | d_1 | d_0 |
| ----------- | ---------------- | ------- | ------- | ------- |
| AP | 758415 | 90.8422 | 91.1373 | 91.3753 |
| AS | 764976 | 83.461 | 83.2508 | 82.7001 |
| BH | 807447 | 84.5168 | 86.2083 | 85.8986 |
| CH | 785384 | 87.4384 | 87.2934 | 87.2649 |
| DL | 859161 | 85.9683 | 85.5766 | 85.9161 |
| GJ | 882817 | 85.6419 | 85.7533 | 86.1285 |
| HP | 203300 | 80.9292 | 80.9608 | 81.32 |
| HR | 255511 | 84.9163 | 85.1213 | 85.1703 |
| JK | 592271 | 84.244 | 84.2937 | 84.6101 |
| KK | 729628 | 88.0607 | 88.1499 | 87.907 |
| KL | 793872 | 80.0359 | 79.5544 | 79.3872 |
| KO | 847638 | 84.6341 | 84.6501 | 84.7638 |
| MB | 687501 | 87.8208 | 85.9449 | 85.9376 |
| MH | 886554 | 95.8487 | 95.6997 | 88.6554 |
| MP | 821474 | 83.1335 | 83.3047 | 83.8239 |
| NE | 824807 | 87.5708 | 87.5969 | 86.8218 |
| OR | 710822 | 84.5128 | 85.2319 | 83.6261 |
| PB | 194300 | 88.798 | 96.5235 | 97.15 |
| RJ | 840310 | 82.438 | 83.7309 | 84.031 |
| TN | 725307 | 90.8855 | 90.7334 | 90.6634 |
| UE | 903366 | 89.8577 | 90.0483 | 90.3366 |
| UW | 729154 | 98.9529 | 87.1339 | 87.8499 |
| WB | 0 | 0 | 0 | 0 |

Related

Output results aggregating column values horizontally

I have this query:
SELECT
count(*), `merchant_id`, `merchant_finance_id`, `merchant_channel_id`, `status`
FROM `application`
WHERE `created_at` >= '2018-04-30' AND `created_at` < '2018-05-01'
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`, `status`
Which results in the following:
-------------------------------------------------------------------------------
| count(*) | merchant_id | merchant_finance_id | merchant_channel_id | status |
-------------------------------------------------------------------------------
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | ACCEPTED |
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | REFERRED |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | AWAITING-ACTIVATION |
| 2 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | DEPOSIT-PAID |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | READY |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | REFERRED |
| 1 | F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | AWAITING-ACTIVATION |
-------------------------------------------------------------------------------
But is there a way I can arranged the status into sub-columns instead? Eg:
-------------------------------------------------------------------------------
| count(*) | merchant_id | merchant_finance_id | merchant_channel_id | accepted | referred | awaiting_activation | deposit_paid | ready
-------------------------------------------------------------------------------
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | 2 | 2 | 0 | 0 | 0 |
| 5 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | 0 | 1 | 1 | 2 | 1 |
| 1 | F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | 0 | 0 | 1 | 0 | 0 |
-------------------------------------------------------------------------------
Note:
There is a defined list of different status types - so I don't have to worry about "BLAHBLAH" somehow being a status type.
You can try to use condition aggregate function, If you use Mysql you can do simplest like this.
SELECT
count(*),
`merchant_id`,
`merchant_finance_id`,
`merchant_channel_id`,
SUM(`status`='ACCEPTED'),
SUM(`status`='REFERRED'),
SUM(`status`='awaiting_activation'),
SUM(`status`='deposit_paid'),
SUM(`status`='READY')
FROM `application`
WHERE `created_at` >= '2018-04-30' AND `created_at` < '2018-05-01'
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`
TestDLL
CREATE TABLE T(
merchant_id varchar(50),
merchant_finance_id varchar(50),
merchant_channel_id varchar(50),
`status` varchar(50)
);
INSERT INTO T VALUES ('D8E2459CD78C', '55E4D520AC1C','66A1861918C5' ,'ACCEPTED');
INSERT INTO T VALUES ('D8E2459CD78C', '55E4D520AC1C','66A1861918C5' ,'REFERRED');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'AWAITING-ACTIVATION');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'DEPOSIT-PAID');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'READY');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'REFERRED');
INSERT INTO T VALUES ('F04FBD7AEB30', 'C11CBD2FC1F8','21F2D435EA9D' ,'AWAITING-ACTIVATION');
Query 1:
SELECT
`merchant_id`,
`merchant_finance_id`,
`merchant_channel_id`,
SUM(`status`='accepted') accepted,
SUM(`status`='referred') referred,
SUM(`status`='awaiting_activation') awaiting_activation,
SUM(`status`='deposit_paid') deposit_paid,
SUM(`status`='ready') ready
FROM T
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`
Results:
| merchant_id | merchant_finance_id | merchant_channel_id | accepted | referred | awaiting_activation | deposit_paid | ready |
|--------------|---------------------|---------------------|----------|----------|---------------------|--------------|-------|
| D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | 1 | 1 | 0 | 0 | 0 |
| E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | 0 | 1 | 0 | 0 | 1 |
| F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | 0 | 0 | 0 | 0 | 0 |

MySQL Join Query without duplicate values

invoice table
SELECT id, fname, gtotal, `date` FROM invoice WHERE id = 1;
| id | fname | gtotal | date |
|----|---------|--------|-----------------------|
| 1 | Brandon | 860 | May, 11 2016 00:00:00 |
invoice_contents table,
SELECT * FROM invoice_contents WHERE invoice_id = 1;
| id | invoice_id | item | price | quantity | discount | total |
|----|------------|------------|-------|----------|----------|-------|
| 1 | 1 | Dextrose | 10 | 10 | 5 | 95 |
| 2 | 1 | Nescaine | 20 | 30 | 10 | 540 |
| 3 | 1 | Anticavity | 30 | 10 | 25 | 225 |
This JOIN query
SELECT invoice.id, invoice.fname, invoice_contents.item,
invoice_contents.price, invoice_contents.quantit,
invoice_contents.discount, invoice_contents.total,
invoice.gtotal
FROM invoice_contents
INNER JOIN invoice ON invoice_contents.invoice_id=1 AND invoice.id=1;
gives this result.
| id | fname | item | price | quantity | discount | total | gtotal |
|----|---------|------------|-------|----------|----------|-------|--------|
| 1 | Brandon | Dextrose | 10 | 10 | 5 | 95 | 860 |
| 1 | Brandon | Nescaine | 20 | 30 | 10 | 540 | 860 |
| 1 | Brandon | Anticavity | 30 | 10 | 25 | 225 | 860 |
I need this result.
| id | fname | item | price | quantity | discount | total | gtotal |
|----|---------|------------|-------|----------|----------|-------|--------|
| 1 | Brandon | Dextrose | 10 | 10 | 5 | 95 | 860 |
| | | Nescaine | 20 | 30 | 10 | 540 | |
| | | Anticavity | 30 | 10 | 25 | 225 | |
I am just a beginner in MySQL. I have been trying from this morning to get this kind of output by experimenting on different combinations please help me out.
#Rex, Your select is correct. You should make desired output using some script e.g. PHP.
try this in SQL:
in this Query i save everytime fname in a variable is not equal and at the next row i compare it and return a empty string is it equal. and the same for gtotal.
the cross join is only to initialize the variables.
in this case it is important that the rows are order by fname to ensure that the same name is behind each other
SELECT
invoice.id,
IF(#last_fname = invoice.fname, '', (#last_fname:=invoice.fname)) as fname,
invoice_contents.item,
invoice_contents.price,
invoice_contents.quantity,
invoice_contents.discount,
IF(#last_gtotal = invoice.gtotal, '', (#last_gtotal:=invoice.gtotal)) as gtotal
FROM invoice_contents
INNER JOIN invoice ON invoice_contents.invoice_id=1 AND invoice.id=1
CROSS JOIN ( select #last_fname := '' , #last_gtotal := '' ) AS parameter
ORDER BY invoice.fname;
Sample
MariaDB [bb]> SELECT
-> invoice.id,
-> IF(#last_fname = invoice.fname, '', (#last_fname:=invoice.fname)) AS fname,
-> invoice_contents.item,
-> invoice_contents.price,
-> invoice_contents.quantity,
-> invoice_contents.discount,
-> IF(#last_gtotal = invoice.gtotal, '', (#last_gtotal:=invoice.gtotal)) AS gtotal
-> FROM invoice_contents
-> INNER JOIN invoice ON invoice_contents.invoice_id=1 AND invoice.id=1
-> CROSS JOIN ( SELECT #last_fname:='' , #last_gtotal:='' ) AS parameter
-> ORDER BY invoice.fname;
+----+---------+------------+-------+----------+----------+--------+
| id | fname | item | price | quantity | discount | gtotal |
+----+---------+------------+-------+----------+----------+--------+
| 1 | Brandon | Dextrose | 10.00 | 10 | 5.00 | 860.00 |
| 1 | | Nescaine | 20.00 | 30 | 10.00 | |
| 1 | | Anticavity | 30.00 | 10 | 25.00 | |
+----+---------+------------+-------+----------+----------+--------+
3 rows in set, 1 warning (0.00 sec)
MariaDB [bb]>

MySQL query with WHERE and CASE

I do not really know if this is possible to do this but I will expose my problem.
I have two tables cases and progress
cases
+----------+--------------+---------------------+---------+------+
| id_cases | name | date_surgery | archive | done |
+----------+--------------+---------------------+---------+------+
| 1 | Cranioplasty | 2016-02-01 00:00:00 | 1 | 0 |
| 2 | Cranioplasty | 2016-02-02 00:00:00 | 0 | 0 |
| 3 | Other | 2016-02-03 00:00:00 | 0 | 0 |
| 4 | Osteotomy | 2016-02-04 00:00:00 | 0 | 0 |
| 5 | Bone Tumor | 2016-02-05 00:00:00 | 1 | 1 |
+----------+--------------+---------------------+---------+------+
progress (which contains thousands of records)
+-------------+---------+---------+---------+
| id_progress | task_id | case_id | current |
+-------------+---------+---------+---------+
| 1 | 103006 | 1 | 0 |
| 2 | 103002 | 1 | 1 |
| 3 | 103003 | 1 | 1 |
| 4 | 201006 | 5 | 0 |
| 5 | 201007 | 5 | 1 |
| .... | ... | ... | ...|
+-------------+---------+---------+---------+
The link between the tables is cases.id_cases = progress.case_id
I want to select all cases with archive and done = 0. I also want to get some progress that are linked to this case
I tought about a condition to select a specific range of task_id related to the result of cases.name.
So basically I want this
SELECT id_cases, name, date_surgery, task_id, current
FROM cases
LEFT JOIN progress on progress.case_id = cases.id_cases
WHERE archive = 0 AND done = 0
But if name is Cranioplasty I just want progress.task_id that are equal to 103006, 103002 and 105002. For Bone Tumor I want 201006, 205003 and 207001. And this for each different name.
There is no logic between the id_cases and the task_id. I must hardcode this.
I tried differents things but none suceeded
SELECT id_Cases, name, date_surgery, task_id, current
from cases
left join progress on progress.case_id = cases.id_cases
where archive = 0 and done = 0
and case when name='Cranioplasty' then task_id=103006 and task_id=103002 else
case when name='Bone Tumor' then task_id=201006 else
case when name='Osteotomy' then task_id=301002 else
case when name='MBIO' then task_id=401006 end end end end
order by name, date_surgery
In fine I try to get this result (task_id is not important, I just want to result of current)
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
| case | name | date_surg | task_1 | 1_res | task_2 | 2_res | task_3 | 3_res |
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
| 1 | Cranioplasty | date | 103006 | 0 | 103002 | 0 | 105002 | 1 |
| 1 | Cranioplasty | date | 103006 | 1 | 103002 | 1 | 105002 | 0 |
| 1 | Cranioplasty | date | 103006 | 1 | 103002 | 0 | 105002 | 1 |
| 2 | Cranioplasty | date | 103006 | 0 | 103002 | 1 | 105002 | 0 |
| 2 | Cranioplasty | date | 103006 | 1 | 103002 | 0 | 105002 | 1 |
| 2 | Cranioplasty | date | 103006 | 0 | 103002 | 1 | 105002 | 1 |
| 3 | Bone Tumor | date | 201006 | 1 | 205003 | 0 | 205005 | 0 |
| 3 | Bone Tumor | date | 201006 | 0 | 205003 | 1 | 205005 | 1 |
| ... | | | | | | | | |
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
PS : I just put my table as an example to help understanding the problem. It does not includes all the records
I know that I can use temporary or virtual table but I wanted to know how to resolve this with only a query
Well, anyway its bad practice to hardcode this relations between name and task id. You need to store them in database or smthng. So you can join that table and do it in 1 query.
If you cant or dont want to its better to save them atleast to an array so you can dynamically generate query part with this conditions if its possible.
select
a.id_cases,
a.name,
b.task_id,
b.current
from
cases a
left join
progress b ON b.case_id = a.id_cases
where
a.archive = 0
and a.done = 0
and (
(b.task_id in (103006,103002,105002) and a.name = 'Cranioplasty')
OR (b.task_id in (201006,205003,207001) and a.name = 'Bone Tumor')
)
If you can use any language to generate this part
and (
(b.task_id in (103006,103002,105002) and a.name = 'Cranioplasty')
OR (b.task_id in (201006,205003,207001) and a.name = 'Bone Tumor')
)
Do it. For example in php
foreach($arRealtions as $name => $taskIDs)
{
$query .= '(b.task_id in ('.implode(',',$taskIDs).') and a.name = "'.$name.'")';
}

MySQL - Time Series Sliding Window

I have a MySQL table containing financial market prices.
+------------+------+--------+--------+--------+--------+
| date | pair | open | high | low | close |
+------------+------+--------+--------+--------+--------+
| 12/9/2009 | 1 | 1.4703 | 1.4783 | 1.4668 | 1.4727 |
| 12/9/2009 | 2 | 1.6287 | 1.6378 | 1.6167 | 1.6262 |
| 12/9/2009 | 3 | 0.9038 | 0.9116 | 0.9015 | 0.9086 |
| 12/9/2009 | 4 | 88.435 | 88.71 | 87.36 | 87.865 |
| 12/9/2009 | 5 | 1.064 | 1.0664 | 1.0515 | 1.0545 |
| 12/10/2009 | 1 | 1.4725 | 1.4761 | 1.4683 | 1.4732 |
| 12/10/2009 | 2 | 1.6261 | 1.6348 | 1.6214 | 1.6279 |
| 12/10/2009 | 3 | 0.9086 | 0.9192 | 0.908 | 0.9166 |
| 12/10/2009 | 4 | 87.87 | 88.47 | 87.73 | 88.2 |
| 12/10/2009 | 5 | 1.0546 | 1.0584 | 1.0479 | 1.0517 |
| 12/11/2009 | 1 | 1.4733 | 1.4778 | 1.4586 | 1.4615 |
| 12/11/2009 | 2 | 1.6278 | 1.634 | 1.6197 | 1.6262 |
| 12/11/2009 | 3 | 0.9164 | 0.9197 | 0.909 | 0.9128 |
| 12/11/2009 | 4 | 88.2 | 89.82 | 88.195 | 89.115 |
| 12/11/2009 | 5 | 1.0517 | 1.0624 | 1.0483 | 1.0602 |
+------------+------+--------+--------+--------+--------+
I want to get something like this. This is filtered by pair (where pair = 1). Every row consists of two consecutive rows.
+--------+--------+--------+--------+--------+--------+--------+--------+
| open1 | high1 | low1 | close1 | open2 | high2 | low2 | close2 |
+--------+--------+--------+--------+--------+--------+--------+--------+
| 1.4703 | 1.4783 | 1.4668 | 1.4727 | 1.4725 | 1.4761 | 1.4683 | 1.4732 |
| 1.4725 | 1.4761 | 1.4683 | 1.4732 | 1.4733 | 1.4778 | 1.4586 | 1.4615 |
+--------+--------+--------+--------+--------+--------+--------+--------+
I tried this query from https://stackoverflow.com/a/5084722/1487781 to get two consecutive dates.
select (
select max(t1.date)
from data as t1
where t1.date < t2.date
and t1.pair = 1
) as date1,
t2.date as date2
from data as t2
It worked but I can't rewrite it to suit my need as I need values and I can't just use max() to do that. Also I need to know how to generalize the solution. For example how if I need three or four consecutive rows.
Try this query:
SELECT d1.date date1,
d2.date date2,
d1.pair,
d1.open open1,
d1.high high1,
d1.low low1,
d1.close close2,
d2.open open2,
d2.high high2,
d2.low low2,
d2.close close2
FROM table1 d1
JOIN table1 d2
ON d1.pair = d2.pair
AND d1.date = d2.date - interval 1 day
Demo: http://www.sqlfiddle.com/#!2/f490d/2
Here is a version with a subquery that determines a next date for given pair number (next date = lowest date that is greater than given date):
SELECT d1.date date1,
d2.date date2,
d1.pair,
d1.open open1,
d1.high high1,
d1.low low1,
d1.close close2,
d2.open open2,
d2.high high2,
d2.low low2,
d2.close close2
FROM table1 d1
JOIN table1 d2
ON d1.pair = d2.pair
AND d2.date = (
SELECT min(date)
FROM table1 t
WHERE t.date > d1.date
AND t.pair = d1.pair
)
demo: --> http://www.sqlfiddle.com/#!2/f490d/9

How to update MySQL table with a cumulative count of events with the same date

I have a table which I pull data from. This data has a date and a stock symbol. There can be multiple rows of data with the same date and different stock symbols. I need to update the table so that there is a running total for all rows with the same date. When a new date occurs the cumulative count re-sets to 1 and then resumes.
A typical query:
mysql> SELECT Sym 'sym' , fdate as 'FilledDate', TsTradeNum 'numT'
-> FROM trades_entered_b2
-> WHERE fDate >= '2009-08-03' AND fDate <= '2009-08-07'
-> LIMIT 10;
+------+------------+------+
| sym | FilledDate | numT |
+------+------------+------+
| WAT | 2009-08-03 | 0 |
| ALGN | 2009-08-04 | 0 |
| POT | 2009-08-05 | 0 |
| PTR | 2009-08-06 | 0 |
| SCHW | 2009-08-06 | 0 |
| FDO | 2009-08-07 | 0 |
| NBL | 2009-08-07 | 0 |
| RRC | 2009-08-07 | 0 |
| WAT | 2009-08-08 | 0 |
| COCO | 2009-08-08 | 0 |
+------+------------+------+
What I want:
+------+------------+------+
| sym | FilledDate | numT |
+------+------------+------+
| WAT | 2009-08-03 | 1 |
| ALGN | 2009-08-04 | 1 |
| POT | 2009-08-05 | 1 |
| PTR | 2009-08-06 | 1 |
| SCHW | 2009-08-06 | 2 |
| FDO | 2009-08-07 | 3 |
| NBL | 2009-08-07 | 4 |
| RRC | 2009-08-07 | 5 |
| WAT | 2009-08-08 | 1 |
| COCO | 2009-08-08 | 2 |
+------+------------+------+
What I need to do is update the TsTradeNum column with the correct values. I have tried to create a function and various queries all failed.
Any ideas? Thanks in advance
Could try below.The query will increment numT by 1 if the previous row date is same with current row, else it will reset numT to 1.
SELECT sym, FilledDate, numT
FROM(
SELECT sym, FilledDate,
#count:=CASE WHEN ( #date <> FilledDate) THEN 1
ELSE
#count+1
END AS numT,
#date:=FilledDate as dlset
FROM
(SELECT #count:= -1) s,
(SELECT #date:= -1) d,
(SELECT id, sym, FilledDate
FROM mytable3
ORDER BY FilledDate,sym desc
) t ) a