Quartiles query in sql - mysql

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

Related

How to calculate percentiles in MySQL with decimals?

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

Mysql query with loop

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

How to make the query for quartile 1, 2, and 3 in MySQL?

I have a query for quartiles like this:
cast(substring_index(substring_index(group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK` ASC separator ','),',',(((50 / 100) * count(0)) + 1)),',',-(1)) as decimal(10,0)) AS `Median`,
cast(substring_index(substring_index(group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK` ASC separator ','),',',(((25 / 100) * count(0)) + 1)),',',-(1)) as decimal(10,0)) AS `Q1`,
cast(substring_index(substring_index(group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK` ASC separator ','),',',(((75 / 100) * count(0)) + 1)),',',-(1)) as decimal(10,0)) AS `Q3`
But this source code is not working for floating values. When I try those codes, the returned value was an integer. What can I do so that the quartile can be seen in integer or float value? Thanks in advance
How about:
you cast the values as decimal(10,0) - the decimal is defined with a precision of 10 digits, but with zero scale.
have a look here: Precision & Scale in MySQL
I changed them to decimal(18,8) in the statement below.
Furthermore, you don't need things like (50 / 100) - just use 0.50
cast(substring_index(
substring_index(
group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK`
ASC separator ','
),',',((0.50 * count(0)) + 1)
),',',-(1)
) as decimal(18,8)
) AS `Median`,
cast(substring_index(
substring_index(
group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK`
ASC separator ','
),',',((0.25 * count(0)) + 1)
),',',-(1)
) as decimal(18,8)
) AS `Q1`,
cast(substring_index(
substring_index(
group_concat(`lulusanmagisterrangkuman`.`IPK`
order by `lulusanmagisterrangkuman`.`IPK`
ASC separator ','
),',',((0.75 * count(0)) + 1)
),',',-(1)
) as decimal(18,8)
) AS `Q3`

Splitting the output of MySQL Group_Concat()

How do I split Group_Concat() result into different columns? I don't want to show it in the same cell separated by comma.
You can use SUBSTRING_INDEX twice after wrapping it in a subquery, in case you know the delimiter.
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 3), '.', -1)
FROM (
SELECT GROUP_CONCAT(...) AS SomeColumn
FROM ...
) AS SomeTable
The first SUBSTRING_INDEX gets the string from first -> n
The second SUBSTRING_INDEX removes the string from first -> n - 1
Check this SQLFiddle example
In your case, if you know the number of columns, your query would look something like (assuming you have 5 strings separated by comma):
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 1), '.', -1)
, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 2), '.', -1)
, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 3), '.', -1)
, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 4), '.', -1)
, SUBSTRING_INDEX(SUBSTRING_INDEX(SomeColumn, '.', 5), '.', -1)
FROM (
SELECT GROUP_CONCAT(...) AS SomeColumn
FROM ...
) AS SomeTable

mysql select substrings and group them by column

I am trying to divide data in one onf the tables on my MySQL database.
Column contains data like this:
de:"Sweatjacke*";en:"jacket*";pl:"bluza*";
de:"*";en:"*";pl:"bluza*";
fr:"*";de:"*";en:"*";pl:"dres junior*";cz:"*";
pl:"bluza";
And I am trying to divide all of the translations into separate columns. Already came with solution to do this by using:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 1), ';', -1) as tr1,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 2), ';', -1) as tr2,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 3), ';', -1) as tr3,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 4), ';', -1) as tr4,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 5), ';', -1) as tr5
FROM product;
statement, but that results in:
tr1 tr2 tr3 tr4 tr5
fr:"*" de:"*" en:"*" pl:"bluza*" cz:"*"
fr:"*" de:"Sweatjacke*" en:"jacket*" pl:"bluza*" cz:"*"
de:"Sweatjacke*" en:"jacket*" pl:"bluza*"
And I want to have the results gruped by translation type (pl/de/en) so in each collumn one type of translatoin is present. For example in column1 = pl:, column2 = en: etc.
Any one came across similar problem and knows a way to solve it?
You need to unpivot the data, then select the first and second part of each value and then re-aggregate it.
However, a better form for the data is really to have language/translation. The following produces this:
select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
You would probably want an "id" column or "word" column to identify each row, rather than the name column.
You can now pivot this result to get what you want:
select max(case when l = 'en' then name end) as en,
max(case when l = 'fr' then name end) as fr,
max(case when l = 'de' then name end) as de,
max(case when l = 'pl' then name end) as pl,
max(case when l = 'cz' then name end) as cz
from (select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
) lt
group by name;
Managed to solve it by using some of the string related functions funcitons:
SELECT
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "pl:", name ) , 150 ) , ';', 1 ) AS pl,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "en:", name ) , 150 ) , ';', 1 ) AS en,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "de:", name ) , 150 ) , ';', 1 ) AS de,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "fr:", name ) , 150 ) , ';', 1 ) AS fr
FROM product
Thanks to everyone for help.
As far as I understand you want to UNPIVOT your data. There is no such function in MySQL, so you might want to export your data into MSSQL (you can use free MSSQL Express) and use UNPIVOT function: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx