I'm using MySQL. I have to separate multi repeated rows into columns. The table has following structure.
But I need like this.
Note: There will be always 6 records of each DateTime. But Title and Feedback are dynamic. I tried to use
select DateTime,
But this is not giving my expected value. I wrote a code (not considered about title):
select
g.dateTime AS dateTime,
g.feedback as feedback ,
c.title AS title
from gauge g
inner join category c on g.category_id=c.category_id AND c.title ='title' AND g.feedback ='feedback'
group by g.dateTime
This doesn't work and I tried GROUP_CONCAT(.... SEPARATOR'.....' ) this gives me not expected output, just gives output in one column. My approach might be wrong.
Use a dynamic pivot since there are many different values
Fiddle to play with
drop table t;
create table t
(
dateTime datetime,
title varchar(50),
feedback int
);
insert into t values
( '2018-06-29 12:55:36', 'A', 1),
( '2018-06-29 12:55:36', 'B', 2),
( '2018-06-22 12:55:36', 'A', 1),
( '2018-06-22 12:55:36', 'B', 2),
( '2018-06-22 12:55:36', 'C', 3);
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN title = ''',
title,
''' THEN ''', title ,''' END) AS ',
CONCAT(' Title',title,',')
),
CONCAT(
'MAX(CASE WHEN feedback = ''',
feedback,
''' THEN ''', feedback ,''' END) AS ',
CONCAT(' Feedback',feedback)
)
) INTO #sql
FROM T;
SET #sql = CONCAT('SELECT dateTime, ', #sql, '
FROM t
GROUP BY dateTime');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I would simply use conditional aggregation. Enumerating the values is a bit tricky in MySQL (unless you are using MySQL 8+):
select datetime,
max(case when rn = 1 then title end) as title_1,
max(case when rn = 1 then feedback end) as feedback_1,
max(case when rn = 2 then title end) as title_2,
max(case when rn = 2 then feedback end) as feedback_2,
max(case when rn = 3 then title end) as title_3,
max(case when rn = 3 then feedback end) as feedback_3,
max(case when rn = 4 then title end) as title_4,
max(case when rn = 4 then feedback end) as feedback_4,
max(case when rn = 5 then title end) as title_5,
max(case when rn = 5 then feedback end) as feedback_5,
max(case when rn = 6 then title end) as title_6,
max(case when rn = 6 then feedback end) as feedback_6
from (select gc.*,
(#rn := if(#dt = g.dateTime, #rn + 1,
if(#dt := g.dateTime, 1, 1)
)
) as rn
from (select g.dateTime, g.feedback, c.title AS title
from gauge g inner join
category c
on g.category_id = c.category_id and
c.title = 'title' and
g.feedback = 'feedback'
group by g.dateTime
order by g.dateTime
) gc cross join
(select #dt := '', #rn := 0) params
) gc
group by datetime;
I don't think the filtering on c.title and g.feedback is correct.
Not an optimized approach but you may join them into table and filter according to row number modulo by 6. This way, we can separate the 6 rows into 6 different table
http://rextester.com/DLVV64095
SELECT MAIN.DateTime,
TBL1.TITLE AS Title1,
TBL1.FEEDBACK AS Feedback1,
TBL2.TITLE AS Title2,
TBL2.FEEDBACK AS Feedback2,
TBL3.TITLE AS Title3,
TBL3.FEEDBACK AS Feedback3,
TBL4.TITLE AS Title4,
TBL4.FEEDBACK AS Feedback4,
TBL5.TITLE AS Title5,
TBL5.FEEDBACK AS Feedback5,
TBL6.TITLE AS Title6,
TBL6.FEEDBACK AS Feedback6
FROM (
SELECT [DATETIME] AS [DateTime]
FROM GAUGE
GROUP BY [DATETIME]
) MAIN
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL1
ON TBL1.DATETIME = MAIN.[DateTime]
AND TBL1.ROWNO % 6 = 1
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL2
ON TBL2.DATETIME = MAIN.[DateTime]
AND TBL2.ROWNO % 6 = 2
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL3
ON TBL3.DATETIME = MAIN.[DateTime]
AND TBL3.ROWNO % 6 = 3
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL4
ON TBL4.DATETIME = MAIN.[DateTime]
AND TBL4.ROWNO % 6 = 4
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL5
ON TBL5.DATETIME = MAIN.[DateTime]
AND TBL5.ROWNO % 6 = 5
INNER JOIN (
SELECT G.DATETIME,
G.FEEDBACK,
C.TITLE,
ROW_NUMBER() OVER(PARTITION BY ORDER BY (SELECT 1) ASC) AS ROWNO
FROM GAUGE G
INNER JOIN CATEGORY C
ON G.CATEGORY_ID = C.CATEGORY_ID
) TBL6
ON TBL6.DATETIME = MAIN.[DateTime]
AND TBL6.ROWNO % 6 = 0
Related
CREATE DEFINER=`root`#`localhost` PROCEDURE `SP_DupAuditCriteria_1`()
BEGIN
set #RowNbr=concat(date_format(curdate(),'%Y%m%d'),'0000000');
select temp.* from
(SELECT c.*, concat(c.VendorID,a.VendorID) as MergeH200A, concat(a.VendorID,c.VendorID) as MergeH200B, 'New' as Record_Type, #RowNbr:= #RowNbr + 1 AS ClaimID
FROM tbldupaudit_currentitems AS c
inner join tbldupaudit_archiveitems a
on c.InvoiceID = a.InvoiceID
and c.GrossAmount = a.GrossAmount) as temp
inner join tbldupaudit_archiveitems b
on temp.InvoiceID = b.InvoiceID
and temp.GrossAmount = b.GrossAmount
and temp.VendorID = b.VendorID
and temp.VoucherID <> b.VoucherID
Union all
select temp1.* from
(SELECT f.*, concat(f.VendorID,d.VendorID) as MergeH200A, concat(d.VendorID,f.VendorID) as MergeH200B, 'ARCHIVE' as Record_Type, 1 AS ClaimID
FROM tbldupaudit_archiveitems AS f
inner join tbldupaudit_currentitems d
on f.InvoiceID = d.InvoiceID
and f.GrossAmount = d.GrossAmount) as temp1
inner join tbldupaudit_currentitems e
on temp1.InvoiceID = e.InvoiceID
and temp1.GrossAmount = e.GrossAmount
and temp1.VendorID = e.VendorID
and temp1.VoucherID <> e.VoucherID
order by InvoiceID, Record_Type DESC;
END
trying make unique ClaimID for each pair. I am able to generate sequential number for first half union all but same ClaimID not able to generate in other half Union all.
Please help me in how to create/generate one unique ID for matched items.
Thank you!]1
In the second select ( after the UNION ALL) you are not incrementing a var so if you want both value incrementeedc the try using a var also for the second
select temp.*
from (
SELECT c.*, concat(c.VendorID,a.VendorID) as MergeH200A, concat(a.VendorID,c.VendorID) as MergeH200B, 'New' as Record_Type
, #RowNbr:= #RowNbr + 1 AS ClaimID
FROM tbldupaudit_currentitems AS c
inner join tbldupaudit_archiveitems a on c.InvoiceID = a.InvoiceID
and c.GrossAmount = a.GrossAmount
) as temp
inner join tbldupaudit_archiveitems b on temp.InvoiceID = b.InvoiceID
and temp.GrossAmount = b.GrossAmount
and temp.VendorID = b.VendorID
and temp.VoucherID <> b.VoucherID
Union all
select temp1.*
from (
SELECT f.*, concat(f.VendorID,d.VendorID) as MergeH200A, concat(d.VendorID,f.VendorID) as MergeH200B, 'ARCHIVE' as Record_Type
, #RowNbr:= #RowNbr + 1 AS ClaimID
FROM tbldupaudit_archiveitems AS f
inner join tbldupaudit_currentitems d on f.InvoiceID = d.InvoiceID
and f.GrossAmount = d.GrossAmount
) as temp1
inner join tbldupaudit_currentitems e on temp1.InvoiceID = e.InvoiceID
and temp1.GrossAmount = e.GrossAmount
and temp1.VendorID = e.VendorID
and temp1.VoucherID <> e.VoucherID
order by InvoiceID, Record_Type DESC;
Modelling example - see fiddle :
SELECT CONCAT( 'prefix', LPAD( CASE #prev
WHEN #prev := InvoiceID
THEN #num
ELSE #num := #num + 1
END, 8, '0' ) ) ClaimID, InvoiceID, Amount, FromTable
FROM ( SELECT InvoiceID, Amount, 'CurrentItems' FromTable
FROM CurrentItems
UNION ALL
SELECT InvoiceID, Amount, 'ArchivedItems'
FROM ArchivedItems
WHERE EXISTS ( SELECT NULL
FROM CurrentItems
WHERE CurrentItems.InvoiceID = ArchivedItems.InvoiceID) ) unioned,
( SELECT #prev := 0, #num := 1000 ) variables
ORDER BY InvoiceID, FromTable DESC;
The below one is my query. It's taking 12 seconds for process. I have created the index for T.DataViewId, but it's still taking long time due to Count(distinct()) and Sum. Thanks in Advance.
;WITH my_cte
AS (SELECT T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM dbo.treehierarchy T
LEFT JOIN dbo.dynamicdatatableid DD
ON T.id = DD.hierarchyid
AND T.dataviewid = DD.dataviewid
LEFT JOIN dbo.demo1 D
ON D.[demo1id] = DD.dynamictableid
WHERE T.dataviewid = 2
AND T.parentid = 0
GROUP BY T.id,
T.name)
SELECT name, id, counts, row_num, measure1
FROM (SELECT name,
id,
counts,
Row_number()
OVER(
ORDER BY counts DESC) AS row_num,
measure1
FROM my_cte) innertable
WHERE ( row_num BETWEEN 1 AND 15 )
It looks as if you only need top 15 records of descending counts. It could be done simply like this :
SELECT
TOP 15 T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM
dbo.treehierarchy T
LEFT JOIN
dbo.dynamicdatatableid DD
ON
T.id = DD.hierarchyid
AND
T.dataviewid = DD.dataviewid
LEFT JOIN
dbo.demo1 D
ON
D.[demo1id] = DD.dynamictableid
WHERE
T.dataviewid = 2
AND
T.parentid = 0
GROUP BY
T.id,T.name
ORDER BY
3 DESC
I have a query in mysql that group concats records and gives a value having redundant tokens. Below is the output of the query:
Problem Area->ACC-HO->ACC-HO->Credit Note (C/N)->Problem description ->Problem description
But I want the distinct tokens of this string as below
Problem Area->ACC-HO->Credit Note (C/N)->Problem description
Is there a way to do this in the sql SELECT query itself?
EDIT
Here is schema and query
Below is my query:
SELECT
t2.transaction_id AS transaction_id,
GROUP_CONCAT(
CONCAT(
t1.display_text,
'->',
(CASE (NOT EXISTS (SELECT 1 FROM mst_node a WHERE a.parent_node_id = t1.node_id))
WHEN 1 THEN t1.display_text ELSE
(SELECT b.display_text AS DISPLAY FROM mst_node b
WHERE parent_node_id = t2.node_id AND b.display_seq = t2.entered_value)
END)
)
ORDER BY t2.logtime_stamp SEPARATOR '->'
) AS display_text
FROM
mst_node t1
JOIN trn_user_log t2
ON t1.app_id = t2.app_id AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
GROUP BY transaction_id,
mobile_no
ORDER BY t2.transaction_id DESC,
t2.logtime_stamp,
t2.mobile_no
In you GROUP CONCAT add DISTINCT so it will only concatenate unique values.
SELECT GROUP_CONCAT(DISTINCT colName),....
FROM ...
WHERE ...
GROUP BY ...
SQLFiddle Demo
in your grouping clause, you can add another group by to group by this string column as well.
SELECT GROUP_CONCAT(myStringColumn),....
FROM ...
WHERE ...
GROUP BY myOtherColumn,myStringColumn
I was finally able to resolve my issue by using a UNION of two select queries and then doing a GROUP_CONCAT(DISTINCT column ORDER BY another_column).
Below is the query I used:
SELECT
transaction_id,
GROUP_CONCAT(DISTINCT display_text ORDER BY logtime_stamp SEPARATOR '->') AS display_text
FROM
(SELECT
t2.transaction_id AS transaction_id,
t2.logtime_stamp,
t1.display_text AS display_text
FROM mst_node t1
JOIN trn_user_log t2 ON t1.app_id = t2.app_id
AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
UNION
SELECT t2.transaction_id AS transaction_id,t2.logtime_stamp,
CASE(NOT EXISTS (SELECT 1 FROM mst_node a WHERE a.parent_node_id = t1.node_id))
WHEN 1 THEN NULL
ELSE (SELECT b.display_text AS display_text FROM mst_node b WHERE parent_node_id = t2.node_id AND b.display_seq = t2.entered_value)
END AS display_text
FROM mst_node t1 JOIN trn_user_log t2
ON t1.app_id = t2.app_id AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
ORDER BY transaction_id DESC,logtime_stamp
) AS T
GROUP BY transaction_id
ORDER BY transaction_id DESC,logtime_stamp
I have a query that basically combines tables of actions and selects from them in chronological order while preserving pagination..
Is there a more efficient / better way to do this? The query takes 3 seconds. Not terrible.. but I think there is room for improvement and I will be using it alot..
Thanks!
SELECT
`newsletters_subscribers`.`email`,
`newsletters_subscribers`.`first_name`,
`newsletters_subscribers`.`last_name`,
`newsletters_subscribers`.`id` AS subscriber_id,
COUNT(DISTINCT newsletters_opens.id) AS opens,
COUNT(DISTINCT newsletters_clicks.id) AS clicks,
COUNT(DISTINCT newsletters_forwards.id) AS forwards
FROM `thebookrackqccom_newsletters_subscribers` newsletters_subscribers
LEFT JOIN
`thebookrackqccom_newsletters_opens` newsletters_opens
ON `newsletters_opens`.`subscriber_id` = `newsletters_subscribers`.`id`
AND newsletters_opens.newsletter_id = 1
LEFT JOIN
`thebookrackqccom_newsletters_clicks` newsletters_clicks
ON `newsletters_clicks`.`subscriber_id` = `newsletters_subscribers`.`id`
AND newsletters_clicks.newsletter_id = 1
LEFT JOIN
`thebookrackqccom_newsletters_forwards` newsletters_forwards
ON `newsletters_forwards`.`subscriber_id` = `newsletters_subscribers`.`id`
AND newsletters_forwards.newsletter_id = 1
WHERE
( newsletters_opens.id IS NOT NULL
OR newsletters_clicks.id IS NOT NULL
OR newsletters_forwards.id IS NOT NULL )
GROUP BY
`newsletters_subscribers`.`id`
ORDER BY
`newsletters_subscribers`.`email` ASC
LIMIT 25
What you need is indexes that the query can use. A compound index on (newsletter_id, subscribe_id) on each one of the three tables would help.
You can also rewrite the query like this:
SELECT
s.email,
s.first_name,
s.last_name,
s.id AS subscriber_id,
COALESCE(o.opens, 0) AS opens,
COALESCE(c.clicks, 0) AS clicks,
COALESCE(f.forwards, 0) AS forwards
FROM thebookrackqccom_newsletters_subscribers AS s
LEFT JOIN
( SELECT subscriber_id,
COUNT(*) AS opens
FROM thebookrackqccom_newsletters_opens
WHERE newsletters_opens.newsletter_id = 1
) AS o ON o.subscriber_id = s.id
LEFT JOIN
( SELECT subscriber_id,
COUNT(*) AS clicks
FROM thebookrackqccom_newsletters_clicks
WHERE newsletter_id = 1
) AS c ON c.subscriber_id = s.id
LEFT JOIN
( SELECT subscriber_id,
COUNT(*) AS forwards
FROM thebookrackqccom_newsletters_forwards
WHERE newsletter_id = 1
) AS f ON f.subscriber_id = s.id
WHERE ( o.subscriber_id IS NOT NULL
OR c.subscriber_id IS NOT NULL
OR f.subscriber_id IS NOT NULL )
ORDER BY
s.email ASC
LIMIT 25
Try this Query i hope you get a better execution time
QUERY
SELECT
`newsletters_subscribers`.`email`,
`newsletters_subscribers`.`first_name`,
`newsletters_subscribers`.`last_name`,
`newsletters_subscribers`.`id` AS subscriber_id,
#nopen := coalesce( N_OPEN.NOPENIDCOUNT, 000000 ) as opens,
#nclick := coalesce( N_CLICK.NCLICKIDCOUNT, 000000 ) as clicks,
#nfwd := coalesce( N_FWD.NFWDIDCOUNT, 000000 ) as forwards
FROM
(select #nopen := 0,#nclick := 0,#nfwd :=0) sqlvars,
`thebookrackqccom_newsletters_subscribers` AS newsletters_subscribers
LEFT JOIN (SELECT `newsletters_opens`.`subscriber_id`,
COUNT(newsletters_opens.id) AS NOPENIDCOUNT
FROM `thebookrackqccom_newsletters_opens` AS newsletters_opens
WHERE newsletters_opens.newsletter_id = 1) AS N_OPEN
ON N_OPEN.subscriber_id = `newsletters_subscribers`.`id`
LEFT JOIN (SELECT `newsletters_clicks`.`subscriber_id`,
COUNT(newsletters_clicks.id) AS NCLICKIDCOUNT
FROM `thebookrackqccom_newsletters_clicks` AS newsletters_clicks
WHERE newsletters_clicks.newsletter_id = 1) AS N_CLICK
ON N_CLICK.subscriber_id = `newsletters_subscribers`.`id`
LEFT JOIN (SELECT `newsletters_forwards`.`subscriber_id`,
COUNT(newsletters_forwards.id) AS NFWDIDCOUNT
FROM `thebookrackqccom_newsletters_forwards` AS newsletters_forwards
WHERE newsletters_forwards.newsletter_id = 1) AS N_FWD
ON N_FWD.subscriber_id = `newsletters_subscribers`.`id`
GROUP BY `newsletters_subscribers`.`id`
ORDER BY `newsletters_subscribers`.`email` ASC
LIMIT 25
I have a union query as follows:
(SELECT t.id, t.name, c.company AS owner, t.creation_date AS date, t.notes
FROM tool t, client c
WHERE t.id_customer = '15' AND t.trash_flag = '1')
UNION
(SELECT f.id, f.name, CONCAT(m.first_name, ' ', m.last_name) AS owner, f.date, f.notes
FROM file f, meta m
WHERE ((f.acl = 0) OR (f.acl = 1 AND '1' = TRUE) OR (f.acl = 2 AND f.id = '7')) AND f.id = '15' AND f.trash_flag = '1' AND m.user_id = f.id_user)
ORDER BY 'name' 'ASC' LIMIT 0,20
Everything works fine but I have two questions:
How do I add a column to the entire result set that gives the row number
Could I do this without using UNION e.g. an advanced join?
Thanks for your time MySQL gurus!
I can't test it righ now but from what I found, following might work:
Reference: Row Number Variable
SQL Statement
SELECT #rownum := #rownum + 1 rownum
, t.*
FROM (
(SELECT t.id
, t.name
, c.company AS owner
, t.creation_date AS date
, t.notes
FROM tool t
, client c
WHERE t.id_customer = '15'
AND t.trash_flag = '1'
) UNION (
SELECT f.id
, f.name
, CONCAT(m.first_name, ' ', m.last_name) AS owner
, f.date
, f.notes
FROM file f
, meta m
WHERE ((f.acl = 0) OR (f.acl = 1 AND '1' = TRUE) OR (f.acl = 2 AND f.id = '7')) AND f.id = '15' AND f.trash_flag = '1' AND m.user_id = f.id_user)
)
) t
, (SELECT #rownum := 0) r
ORDER BY
'name' ASC
LIMIT 0, 20