alternate of group_concat function in mysql - mysql

I need some comma separated values for one of my column :
Input :
id status
1. pause
1. start
1. running
2. pause
3. pause
Output:
id. status
1. pause,start,running
2. pause
3. pause
I do not want to use the group_concat function here as in future in it can be possible that will be using another type of database (sql/nosql).Can anyone help me to use any alternate method?

WITH RECURSIVE
cte1 AS (
SELECT id, status,
ROW_NUMBER() OVER (PARTITION BY id) rn
FROM test
),
cte2 AS (
SELECT id, rn,
CAST(status AS CHAR(65535)) csv
FROM cte1
WHERE rn = 1
UNION ALL
SELECT cte1.id, cte1.rn,
CONCAT_WS(',', cte2.csv, cte1.status)
FROM cte2
JOIN cte1 ON cte1.id = cte2.id AND cte1.rn = cte2.rn + 1
),
cte3 AS (
SELECT id, csv,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY rn DESC) rn
FROM cte2
)
SELECT id, csv
FROM cte3
WHERE rn = 1
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0713abe3711c98c91dd1ceadb533e968
Another DBMSs needs minimal changes when adapting this query. Removing RECURSIVE from WITH clause definition, replacing CONCAT_WS() with according function (or maybe using common concatenation if statusis not nullable), removing explicit CAST in recursive CTE or changing the datatype...
PS. Another DBMSs have the function which is an analog of GROUP_CONCAT() in MySQL, or at least they have some specific constructions/methods for to perform such task.

Related

How to select only one type of value for shared id?

I wasn't sure how to word this but this is what I am looking for:
Currently my table looks like this:
On MySQL 8+, we can use RANK():
WITH cte AS (
SELECT *, RANK() OVER (PARTITION BY common_id ORDER BY id) rnk
FROM yourTable
)
SELECT id, string, common_id
FROM cte
WHERE rnk = 1;

mysql query to group record and generate custom columns

So i have a table named "log" with the following columns,
id, endpoint ,response ,group
SAMPLE DATA.
1. endpoint1 ,{"last_name":"data here"} ,1234
2. endpoint2 ,{"first_name":"data here"} ,1234
3. endpoint3 ,{"dob":"12-21-2301"} ,1234
what I want to achieve is to write a query that can generate a record grouped by the "
group" column and the final output should be something like this.
{"last_name","data here","first_name":"data here","dob":"12-21-2301"}
for each record with each key been a column.
Thank you
WITH RECURSIVE
cte1 AS ( SELECT response,
`group`,
ROW_NUMBER() OVER (PARTITION BY `group`) rn
FROM log ),
cte2 AS ( SELECT response,
`group`,
rn
FROM cte1
WHERE rn = 1
UNION ALL
SELECT JSON_MERGE_PRESERVE(cte1.response, cte2.response),
cte1.`group`,
cte1.rn
FROM cte2
JOIN cte1 USING (`group`)
WHERE cte2.rn + 1 = cte1.rn )
SELECT DISTINCT
FIRST_VALUE(response) OVER (PARTITION BY `group` ORDER BY rn DESC) responses,
`group`
FROM cte2;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=913b1923d7d5dbc7e42baeefb6e6ec86

SQL Query about percentage selection

I am trying to write a query for a condition:
If >=80 percent (4 or more rows as 4/5*100=80%) of the top 5 recent rows(by Date Column), for a KEY have Value =A or =B, then change the flag from fail to pass for the entire KEY.
Here is the input and output sample:
I have highlighted recent rows with green colour in the sample.
Can someone help me in this?
I tried till finding the top 5 recent rows by the foll code:
select * from(
select *, row_number() over (partition by "KEY") as 'RN' FROM (
select * from tb1
order by date desc))
where "RN"<=5
Couldnt figure what to be done after this
Test this:
WITH
-- enumerate rows per key group
cte1 AS ( SELECT *,
ROW_NUMBER() OVER (PARTITION BY `key` ORDER BY `date` DESC) rn
FROM sourcetable ),
-- take 5 recent rows only, check there are at least 4 rows with A/B
cte2 AS ( SELECT `key`
FROM cte1
WHERE rn <= 5
GROUP BY `key`
HAVING ( SUM(`value` = 'A') >= 4
OR SUM(`value` = 'B') >= 4 )
-- AND SUM(rn = 5) )
-- update rows with found key values
UPDATE sourcetable
JOIN cte2 USING (`key`)
SET flag = 'PASS';
5.7 version – Ayn76
Convert CTEs to subqueries. Emulate ROW_NUMBER() using user-defined variable.

How to filter out results on the basis of odd and even row number using window functions, no existing column as Row ID

I am currently using the following code, but it is not working, Please guide me-
select name, Continent, LifeExpectancy
from world.country
where mod(Row_Number()
over(order by Continent),2)=0;
You typically would need a subquery here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Continent) rn
FROM world.country
)
SELECT name, Continent, LifeExpectancy
FROM cte
WHERE rn % 2 = 0; -- for evens
You can make a subquery to use the WINDOW funtion.
Can you pls try this ?
select name, Continent
from (
select name, Continent, LifeExpectancy, Row_Number() over(order by Continent) rn
from world.country) rs
where mod(rs.rn,2)=0;

Get the last record from each month, from each MATERIAL id after a rolling sum

I have a table which I need to perform a rolling sum for each material. I've already done it using this:
SELECT *, SUM(`ESTOQUE_FINAL`) OVER (PARTITION BY MATERIAL ORDER BY CALDAY) as ESTOQUE
FROM bq_trusted.IINV_01
ORDER BY MATERIAL, CALDAY
The result is
in this screenshot
What i need now is to get the results on the red circled values. For each MATERIAL, I need the result of the rolling sum by the end of each month.
I can get those results using the following query, but I have to save the last query on a new table to use it.
WITH ESTOQUE_ATUAL AS (
SELECT IQ.*, ROW_NUMBER() OVER (PARTITION BY MATERIAL, MONTH_YEAR ORDER BY CALDAY DESC) AS RN
FROM bq_trusted.INVENTORY AS IQ
)
SELECT * FROM ESTOQUE_ATUAL WHERE RN = 1
ORDER BY MONTH_YEAR
How can I achieve this result using only one query?
Thanks in advance!
Is this what you want?
SELECT i.*
FROM (SELECT i.*,
SUM(ESTOQUE_FINAL) OVER (PARTITION BY MATERIAL ORDER BY CALDAY) as ESTOQUE,
ROW_NUMBER() OVER (PARTITION BY MATERIAL, MONTH_YEAR ORDER BY CALDAY DESC) AS seqnum
FROM bq_trusted.IINV_01 i
) i
WHERE seqnum = 1
ORDER BY MATERIAL, CALDAY
You can calculate both window functions at the same time.