I need some help on MySQL Query for UNION multiple Tables and group the result by ID and output the result in JSON_ARRAY. I have referred to this but I can't get the output as I want because my query need to UNION tables.
SELECT
JSON_ARRAYAGG(JSON_OBJECT(
'_CODE', a._CODE,
'_USERID', a._USERID,
'_NAME', c._NAME,
'HAHA',
(SELECT JSON_ARRAY(JSON_OBJECT(
'_CAT', b._CAT,
'_MODEL', b._MODEL,
'_SERIAL', b._SERIAL,
'_IPADDR', b._IPADDR,
'_OS', (SELECT _DESC
FROM kod_produk
WHERE _CODE = (SELECT _PROD
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '15'
AND _SERIAL = b._SERIAL)),
'_AV', (SELECT CONCAT(_DESC,
' (',
(CASE WHEN(SELECT _CODE
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '16'
AND _EXPY_DATE > NOW())
IS NOT NULL
THEN
'AKTIF'
ELSE
'TAMAT'
END), ')')
FROM kod_produk
WHERE _CODE = (SELECT _PROD
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '16'
AND _SERIAL = b._SERIAL))
)))
)) Z
FROM
inventori_mt a
LEFT JOIN
(
SELECT _CODE, _CAT, _MODEL, _SERIAL, _IPADDR FROM inventori_dt1
UNION ALL
SELECT _CODE, _CAT, _MODEL, _SERIAL, _IPADDR FROM inventori_dt2
) b ON a._CODE = b._CODE
LEFT JOIN
sys_pengguna c ON a._USERID = c._USERID
Table design
Pastebin
Expected Result
Actual Output Result
DB-Fiddle
Sample DB
Need to use JSON_ARRAY() with JSON_ARRAYAGG() within the subquery, and use GROUP BY expression within the one level outer query with JSON_OBJECT() function at topmost of this query in order to get each individual grouped, and nested objects. And apply JSON_ARRAYAGG() at the outermost level in order to aggregate all those independent JSON object pieces. So, use :
SELECT JSON_PRETTY( JSON_ARRAYAGG(Z) ) AS Z
FROM
(
SELECT
JSON_OBJECT(
'_CODE', a._CODE,
'_USERID', a._USERID,
'_NAME', c._NAME,
'HAHA',
(SELECT
JSON_ARRAYAGG(
JSON_OBJECT(
'_CAT', b._CAT,
'_MODEL', b._MODEL,
'_SERIAL', b._SERIAL,
'_IPADDR', b._IPADDR ,
'_OS', (SELECT _DESC
FROM kod_produk
WHERE _CODE = (SELECT _PROD
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '15'
AND _SERIAL = b._SERIAL)),
'_AV', (SELECT CONCAT(_DESC,
' (',
(CASE WHEN(SELECT _CODE
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '16'
AND _EXPY_DATE > NOW())
IS NOT NULL
THEN
'AKTIF'
ELSE
'TAMAT'
END), ')')
FROM kod_produk
WHERE _CODE = (SELECT _PROD
FROM inventori_dt3
WHERE _CODE = a._CODE
AND _CAT = '16'
AND _SERIAL = b._SERIAL))
)
)
)
) Z
FROM inventori_mt a
LEFT JOIN
(
SELECT _CODE, _CAT, _MODEL, _SERIAL, _IPADDR FROM inventori_dt1
UNION ALL
SELECT _CODE, _CAT, _MODEL, _SERIAL, _IPADDR FROM inventori_dt2
) b
ON a._CODE = b._CODE
LEFT JOIN sys_pengguna c
ON a._USERID = c._USERID
GROUP BY a._CODE, a._USERID, c._NAME
) q
Demo
Related
I have a query that is giving me different results when i enclosed it in Parentheses, however when I run it without Parentheses its giving me different results. I want to apply Union in between so I have to use Parentheses as without union doesn't work.
The query is as follows:
SELECT Distinct
recurring_billing.id,
recurring_billing.kid_id,
recurring_billing.class_id,
recurring_billing.app_id,
recurring_billing.Region_ID,
CC.month_name,
CC.billing_year,
CASE
WHEN
CC.month_name = recurring_billing.billing_month
AND CC.billing_year = recurring_billing.billing_year
THEN
recurring_billing.billing_status
ELSE
'Pending'
END
AS billing_status, tblkids.kid_name, tblkids.kid_Lastname, tblkids.kid_EMail, tbl_app.app_CCExp AS cc_exp, tbl_app.app_CCName AS cc_name, tbl_app.app_CCNumber AS cc_number, tbl_app.app_CCType AS cc_type, tblclasses.cla_EndDate, tblclassdays.classday_day, CC.remainingclasses, tbl_app.cost_per_class, CC.remainingclasses * tbl_app.cost_per_class AS cost_amount,
CASE
WHEN
OP.override_amt IS NOT NULL
THEN
OP.override_amt
ELSE
CC.remainingclasses * tbl_app.cost_per_class
END
AS pmt_amount,
CASE
WHEN
OP.process_payment = False
THEN
OP.process_payment
ELSE
True
END
AS process_payment
FROM
recurring_billing
LEFT JOIN
tblkidsxclass
ON recurring_billing.kid_id = tblkidsxclass.kxc_kidid
AND recurring_billing.app_id = tblkidsxclass.kxc_appid
LEFT JOIN
tbl_app
ON recurring_billing.app_ID = tbl_app.app_ID
LEFT JOIN
tblkids
ON recurring_billing.kid_id = tblkids.kid_ID
LEFT JOIN
tblclasses
ON recurring_billing.class_id = tblclasses.cla_ID
LEFT JOIN
tblclassdays
ON tblclasses.cla_ID = tblclassdays.classday_classID
INNER JOIN
(
SELECT
MONTHNAME(classday_day) AS month_name,
YEAR(classday_day) AS billing_year,
cla_ID,
COUNT(classday_classid) AS remainingclasses,
c.cost_per_class AS cost_per_class,
COUNT(classday_classid) * cost_per_class AS TotalClassCost
FROM
tblclassdays
JOIN
(
SELECT
tblclasses.cla_ID,
tblclasses.cost_per_class,
tblclasses.cla_nextclass AS next1,
tblclasses_1.cla_nextclass AS next2
FROM
tblclasses
LEFT JOIN
tblclasses AS tblclasses_1
ON tblclasses.cla_nextclass = tblclasses_1.cla_ID
WHERE
tblclasses.cla_ID IN
(
SELECT DISTINCT
recurring_billing.class_id
FROM
recurring_billing
LEFT JOIN
tblkidsxclass
ON recurring_billing.kid_id = tblkidsxclass.kxc_kidid
AND recurring_billing.app_id = tblkidsxclass.kxc_appid -- LEFT JOIN tblkids ON recurring_billing.kid_id = tblkids.kid_ID
LEFT JOIN
tblclasses
ON recurring_billing.class_id = tblclasses.cla_ID -- LEFT JOIN tblclassdays ON tblclasses.cla_ID = tblclassdays.classday_classID
WHERE
ISNULL(tblkidsxclass.kxc_dropoutdate)
AND tblkidsxclass.pmt_option = 'Recurring'
AND tblclasses.cla_active = TRUE -- AND tblclasses.cla_EndDate >= NOW()
GROUP BY
recurring_billing.id
)
)
c
ON tblclassdays.classday_classid IN
(
c.cla_ID,
c.next1,
c.next2
)
WHERE
tblclassdays.classday_noclass = FALSE
AND MONTH(classday_day) = 11
AND YEAR(classday_day) = 2020
AND
(
CONCAT(CAST(classday_day AS DATE), ' ', CAST(classday_endtime AS TIME)) > CAST(CURDATE() AS DATETIME)
)
GROUP BY
cla_ID
)
CC
ON CC.cla_ID = tblclassdays.classday_classID
LEFT JOIN
override_payments OP
ON recurring_billing.app_id = OP.app_id
AND recurring_billing.kid_id = OP.kid_id
AND CC.month_name = OP.billing_month
AND CC.billing_year = OP.billing_year
WHERE
ISNULL(tblkidsxclass.kxc_dropoutdate)
AND tblkidsxclass.pmt_option = 'Recurring'
AND tblclasses.cla_active = TRUE
AND recurring_billing.kid_id NOT IN
(
SELECT
kid_id
from
recurring_billing
where
billing_month = 'November'
and billing_year = '2020'
)
-- AND tblclasses.cla_EndDate >= NOW()
GROUP BY
recurring_billing.id
ORDER BY
recurring_billing.id ASC
Same query if enclosed in Parentheses will give me different results.
Parentheses are not required for a UNION statement. The following 2 union statements both work and yield the same results.
SELECT 1 UNION SELECT 2;
(SELECT 1) UNION (SELECT 2);
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;
SELECT
SUM(m_out) AS totalOut
FROM
m_detal
WHERE
opers = '25'
AND (m_type = 'Out'
OR m_type = 'Merged')
AND m_date <= '2018-11-28 07:30:00'
AND mark_delete IS NULL
AND m_ids NOT IN (SELECT
m.m_ids
FROM
(SELECT
m_ids
FROM
m_detal
WHERE
opers = '25'
AND (m_type = 'Out'
OR m_type = 'Merged')
AND (m_onhold != 'onhold'
OR m_onhold IS NULL)
AND mark_delete IS NULL
AND m_date <= '2018-11-28 07:30:00') AS m
INNER JOIN
n_combine_tbl AS t ON (t.comb_id1 = m.m_ids
OR t.comb_id2 = m.m_ids)
AND t.time <= '2018-11-28 07:30:00');
This query took me more than 30sec or more! The query inside the NOT IN is little bit huge around 7-9k of ids. Is there a more efficient way of doing this? I think the inner join part is make it slow where the checking the two column of n_combine_tables which is (comb_id1 or comb_id2).
Is there a more efficient way of doing this?
I'd remove duplicated conditions in sub-queries and do something like this (two NOT in could be replaced with UNION):
SELECT
SUM(m.m_out) AS totalOut
FROM
m_detal AS m
WHERE
m.opers = '25'
AND m.m_type IN ('Out', 'Merged')
AND m.m_date <= '2018-11-28 07:30:00'
AND m.mark_delete IS NULL
AND m.m_onhold = 'onhold'
AND m.m_ids NOT IN (
SELECT
t1.comb_id1
FROM
n_combine_tbl AS t1
WHERE
t1.time <= '2018-11-28 07:30:00'
)
AND m.m_ids NOT IN (
SELECT
t2.comb_id2
FROM
n_combine_tbl AS t2
WHERE
t2.time <= '2018-11-28 07:30:00'
)
;
OR with NOT EXISTS:
SELECT
SUM(m.m_out) AS totalOut
FROM
m_detal AS m
WHERE
m.opers = '25'
AND m.m_type IN ('Out', 'Merged')
AND m.m_date <= '2018-11-28 07:30:00'
AND m.mark_delete IS NULL
AND m.m_onhold = 'onhold'
AND NOT EXISTS (
SELECT
*
FROM
n_combine_tbl AS t
WHERE
t.time <= '2018-11-28 07:30:00'
AND (
t.comb_id1 = m.m_ids
OR t.comb_id2 = m.m_ids
)
)
;
You should check the 'onhold' logic.
You should try to add indexes on n_combine_tbl: (time, comb_id1), (time, comb_id2), (comb_id1, time), (comb_id2, time) and check what is good for your data.
Multi-column indexes on m_detal table should also be considered.
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
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