I am want to archive daily price statistics in MySQL 5.6 where I also use 25/50/75 percentiles. The formulas I found seem to work but are rounded to integers.
How can I get the 25/50/75 percentiles of price with 2 decimals precision?
INSERT INTO prices_daily
(DATE, ID, PRICE_MIN, PRICE_MAX, PRICE_AVG, `PRICE_25PZTL`, `PRICE 50PZTL`, `PRICE_75PZTL`, STRENGTH)
SELECT
DATE,
ID,
ROUND(MIN(price),2) AS PRICE_MIN,
ROUND(MAX(price),2) AS PRICE_MAX,
ROUND(AVG(price),2) AS PRICE_AVG,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY price SEPARATOR ','), ',', 25/100 * COUNT(*) + 1), ',', -1) AS DECIMAL) AS 'PRICE_25PZTL',
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY price SEPARATOR ','), ',', 50/100 * COUNT(*) + 1), ',', -1) AS DECIMAL) AS 'PRICE_50PZTL',
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY price SEPARATOR ','), ',', 75/100 * COUNT(*) + 1), ',', -1) AS DECIMAL) AS 'PRICE_75PZTL',
count(ID) AS STRENGTH
FROM
`articles`
WHERE
DATE = CURDATE()
GROUP BY
DATE,
ID
ORDER BY
STRENGTH DESC
Related
I have this query, works fine for view and csv export from phpmyadmin.
Is possible create a loop without repeat? thanks!
SELECT
id, date, name,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '-', 1), '(', -1) AS op,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '-', 4), '-', -3) AS dt,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, ')', 1), '-', -1) AS hour,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '(', 2), '-', -1) AS note
FROM center
WHERE center.date BETWEEN '2019-08-01 00:00:00' AND '2019-12-31 00:00:00'
and message!= ''
HAVING op = 'op1' OR op = 'op2'
UNION SELECT
id, date, name,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '-', 6), '(', -1) AS op,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '-', 9), '-', -3) AS dt,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, ')', 2), '-', -1) AS hour,
SUBSTRING_INDEX(SUBSTRING_INDEX(message, '(', 3), '-', -1) AS note
FROM center
WHERE center.date BETWEEN '2019-08-01 00:00:00' AND '2019-12-31 00:00:00'
and message!= ''
HAVING op = 'op1' OR op = 'op2'
UNION SELECT.... more
You can test this Query. It split a max. of 10 pieces from a row.
SELECT `id`,`date`,`name`,CONCAT('op',`op`) as op,`dt`,`hour`,`note`
,subid,cols -- only for test. you can remove this line
FROM (
SELECT c.id,c.date,c.name,
cnt.*,
-- count the pieces in one row
(LENGTH(message)-LENGTH(replace(message,'(op','')))/3 as cols,
-- Split String in piece and store in #content
#content := SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(' (op ',c.message,' (op'), ' (op', subid+3), ' (op', -1)
, SUBSTRING_INDEX(#content, ' - ',1) as op
, SUBSTRING_INDEX( SUBSTRING_INDEX(#content, ' - ',2), ' - ',-1) as dt
, TRIM( TRAILING ')' FROM SUBSTRING_INDEX( SUBSTRING_INDEX(#content, ' - ',3), ' - ',-1)) as hour
, SUBSTRING_INDEX( SUBSTRING_INDEX(#content, ' - ',4), ' - ',-1) as note
FROM center c
CROSS JOIN (
SELECT 0 as subid UNION ALL SELECT 1 UNION ALL SELECT 2
UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5
UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9
) as cnt
) as result
WHERE
subid < cols
AND `date` BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
AND op in (1,2)
ORDER BY id,subid,cols;
Here is a Sample : http://www.sqlfiddle.com/#!9/8bc3b4/60
My Following Query gives the result according to my record but what i have the problem is my query is generating some different serial number .Anyways i need the serial number to start from 1 but this query is join query is shows different serial number like i can say during joining it skips the series .
Kindly help to generate the series from 1 to number of rows from db without skipping the series in between. Thanks in Advance
SELECT
#a:=#a+1 sno,
p.po_no as id,
DATE_FORMAT(p.po_date, '%d-%m-%Y') as po_date,
p.customer,
p.cust_po as po_no,
p.tot_ord_qty,
DATE_FORMAT(p.delivery_date, '%d-%m-%Y') AS delivery_date,
p.dc_status,
p.inv_status,
p.tot_dc_qty,
p.tot_inv_qty,
COALESCE(GROUP_CONCAT(distinct d.dc_no SEPARATOR ', '), 0) as dc,
GROUP_CONCAT( d.active SEPARATOR ', ') as status
FROM (SELECT #a:= 0) AS a, po_header p
LEFT JOIN dc_details d
ON p.cust_po = d.cust_po
group by
p.cust_po
Result:
The reason you're skipping numbers is because of GROUP BY. Grouping is done after the serial numbers are generated, so it combines all the rows with the same cust_po and you only see one of the serial numbers.
Move the grouping into a subquery and add the serial numbers in the main query.
SELECT #a := #a+1 AS sno, t.*
FROM (SELECT #a := 0) AS a
CROSS JOIN (
SELECT p.po_no as id,
DATE_FORMAT(p.po_date, '%d-%m-%Y') as po_date,
p.customer,
p.cust_po as po_no,
p.tot_ord_qty,
DATE_FORMAT(p.delivery_date, '%d-%m-%Y') AS delivery_date,
p.dc_status,
p.inv_status,
p.tot_dc_qty,
p.tot_inv_qty,
COALESCE(GROUP_CONCAT(distinct d.dc_no SEPARATOR ', '), 0) as dc,
GROUP_CONCAT( d.active SEPARATOR ', ') as status
FROM po_header AS p
LEFT JOIN dc_details AS d ON p.cust_po = d.cust_po
GROUP BY p.cust_po
ORDER BY p.cust_po) AS t
I have code like this:
SELECT `pelamarmagisterrangkuman`.`major` AS `ProgramStudi`,
count(IPKS1) as N,
AVG(IPKS1) as Mean,
MIN(IPKS1) as Minimum,
MAX(IPKS1) as Maximum,
StdDev(IPKS1) as StDev,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(
GROUP_CONCAT(IPKS1 ORDER BY IPKS1 SEPARATOR ','),
',', 50/100 * COUNT(*) + 1), ',', -1) AS decimal) AS `Median`,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(
GROUP_CONCAT(IPKS1 ORDER BY IPKS1 SEPARATOR ','),
',', 25/100 * COUNT(*) + 1), ',', -1) AS decimal) AS `Q1`,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(
GROUP_CONCAT(IPKS1 ORDER BY IPKS1 SEPARATOR ','),
',', 75/100 * COUNT(*) + 1), ',', -1) AS decimal) AS `Q3`
FROM `pelamarmagisterrangkuman` where `pelamarmagisterrangkuman`.`IPKS1` != 0 and `pelamarmagisterrangkuman`.`TahunDaftar` = 2012 group by `pelamarmagisterrangkuman`.`major`
COUNT, AVG, MIN, MAX, and MIN can work properly. But, quartiles cannot work properly. I mean, the result of the code above is integer values. But, the result that I expected is not just integer value, but also float value because my data is in float and integer value. What may I do to fix that? Thanks in advance
Avoid integers in the arithmetic e.g.
50.0/100.0 * cast(COUNT(*) as decimal) + 1.0
I`m trying to solve this challenge:
https://www.hackerrank.com/challenges/the-pads
My solution is this in MySQL:
(SELECT CONCAT(Name,'(',SUBSTR(Occupation,1,1),')') FROM Occupations ORDER BY Name)
UNION
(SELECT CONCAT('There are total ', COUNT(Occupation), ' ',LOWER(Occupation),'s.') AS total FROM Occupations
GROUP BY Occupation
ORDER BY total);
However it fails to ORDER BY total.
Ashley(P)
Samantha(A)
Julia(D)
Britney(P)
Maria(P)
Meera(P)
Priya(D)
Priyanka(P)
Jennifer(A)
Ketty(A)
Belvet(P)
Naomi(P)
Jane(S)
Jenny(S)
Kristeen(S)
Christeen(S)
Eve(A)
Aamina(D)
There are total 4 actors.
There are total 3 doctors.
There are total 7 professors.
There are total 4 singers.
If I only run
SELECT CONCAT('There are total ', COUNT(Occupation), ' ',LOWER(Occupation),'s.') AS total FROM Occupations
GROUP BY Occupation
ORDER BY total
it does order:
There are total 3 doctors.
There are total 4 actors.
There are total 4 singers.
There are total 7 professors.
The result gets ordered by the final ORDER BY clause. This is ORDER BY total, i.e. by the first column. (You only give this name in the second part of UNION, which would probably not work in another DBMS. You should name the columns you select in a UNION query in the first part.)
You want to get names first, then the aggregates. Then you want names alphabetically, aggregates by count (i.e. not alphabetically, not 1 -> 10 -> 11 -> 2 -> 20 ..., but 1 -> 2 -> 10 -> 11 -> 20 ...) then by job name. You can create sortkeys for this task. I assume you really want UNION ALL, not UNION. If I am wrong, change it :-)
SELECT txt
FROM
(
SELECT
CONCAT(Name, '(', SUBSTR(Occupation, 1, 1), ')') as txt,
1 as sortkey1,
CONCAT(Name, '(', SUBSTR(Occupation, 1, 1), ')') as sortkey2
FROM Occupations
UNION ALL
SELECT
CONCAT('There are total ', COUNT(Occupation), ' ', LOWER(Occupation), 's.') AS txt,
2 + COUNT(Occupation) as sortkey1,
LOWER(Occupation) as sortkey2
FROM Occupations
GROUP BY Occupation
) data
ORDER BY sortkey1, sortkey2;
That is correct. The ordering of the result set is based only on the outermost order by. This is true for union as for other operations.
(SELECT CONCAT(Name,'(', SUBSTR(Occupation,1,1),')') AS total
FROM Occupations
ORDER BY Name
)
UNION ALL
(SELECT CONCAT('There are total ', COUNT(Occupation), ' ', LOWER(Occupation), 's.') AS total
FROM Occupations
GROUP BY Occupation
)
ORDER BY (CASE WHEN total LIKE 'There are total%' THEN 1 ELSE 0 END),
Total;
This assumes that Name never starts with 'There are total', which seems likely.
#gordon answer is fine
But for a more generic case you have to create a "dummy" field to separate each group.
(SELECT CONCAT(Name,'(', SUBSTR(Occupation,1,1),')') as Name,
0 as dummy
FROM Occupations
)
UNION ALL
(SELECT CONCAT('There are total ', COUNT(Occupation), ' ', LOWER(Occupation), 's.') AS Name,
1 as dummy
FROM Occupations
GROUP BY Occupation
)
ORDER BY dummy, name
Based on the answers and my best understanding I came with this solution that works for this case:
(SELECT CONCAT(Name,'(',SUBSTR(Occupation,1,1),')') as total FROM Occupations ORDER BY Name)
UNION ALL
(SELECT CONCAT('There are total ', COUNT(Occupation), ' ',LOWER(Occupation),'s.') AS total FROM Occupations
GROUP BY Occupation)
ORDER BY total;
This worked for me.
you can give two different select queries whith out UNION/ UNION ALL.
SELECT Concat(NAME, '(', Substr(occupation, 1, 1), ')') AS Result
FROM occupations
ORDER BY NAME;
SELECT Concat('There are a total of ', Count(*), ' ', Lower(occupation), 's.')
FROM occupations
GROUP BY occupation
ORDER BY Count(*), occupation;
I am trying to get 5 latest order timings of customers using:
SET SESSION group_concat_max_len = 99;
select o.customer_id, substring_index(m.orders,',', 1) as order1,
(case when numc >=2 then substring_index(substring_index(m.orders, ',', 2), ',', -1)end) as order2,
(case when numc >=3 then substring_index(substring_index(m.orders, ',', 3), ',', -1)end) as order3,
(case when numc >=4 then substring_index(substring_index(m.orders, ',', 4), ',', -1)end) as order4,
(case when numc >=5 then substring_index(substring_index(m.orders, ',', 5), ',', -1)end) as order5
from orders o,
(select group_concat(date order by date desc) as orders, count(*) as numc
FROM orders) m
where country_id='27'
group by customer_id
But it is returning me sysdate for all customers.
Where am i doing it wrong?
I'm not sure what you mean by "sysdate for all customers". But, the join is not doing what you expect.
Just do the aggregation once:
select o.customer_id, substring_index(group_concat(date order by date desc),',', 1) as order1,
(case when count(*) >=2 then substring_index(substring_index(group_concat(date order by date desc), ',', 2), ',', -1)end) as order2,
(case when count(*) >=3 then substring_index(substring_index(group_concat(date order by date desc), ',', -1)end) as order3,
(case when count(*) >=4 then substring_index(substring_index(group_concat(date order by date desc), ',', 4), ',', -1)end) as order4,
(case when count(*) >=5 then substring_index(substring_index(group_concat(date order by date desc), ',', 5), ',', -1)end) as order5
from orders o
where country_id='27'
group by customer_id