Union ALL sum results in one row and keep summed values - sql

I am trying to build a query which gets sum of different kinds of replications per user. I want to show a unified result with rows with each replication and another row which sums them into an all per user. Here is the query:
SELECT replica_name,
user_id,
short_name,
number_of_replications,
firstReplication,
lastReplication
FROM (SELECT 'Initial' AS replica_name,
sc.user_id AS user_id,
u.short_name AS short_name,
Count(sc.user_id) AS number_of_replications,
Min(sc.connected_at) AS firstReplication,
Max(sc.connected_at) AS lastReplication
FROM phoenix.synchro_connections sc
JOIN phoenix.users u
ON u.user_id = sc.user_id
WHERE Lower(sc.synchro_type) = 'initial'
AND sc.size_in_bytes IS NOT NULL
GROUP BY sc.user_id,
u.short_name,
sc.synchro_type
UNION ALL
SELECT 'Delta' AS replica_name,
sc.user_id AS user_id,
u.short_name AS short_name,
Count(sc.user_id) AS number_of_replications,
Min(sc.connected_at) AS firstReplication,
Max(sc.connected_at) AS lastReplication
FROM phoenix.synchro_connections sc
JOIN phoenix.users u
ON u.user_id = sc.user_id
WHERE Lower(sc.synchro_type) = 'delta'
AND sc.size_in_bytes IS NOT NULL
GROUP BY sc.user_id,
u.short_name,
sc.synchro_type
UNION ALL
SELECT 'All' AS replica_name,
sc.user_id AS user_id,
u.short_name AS short_name,
Count(sc.user_id) AS number_of_replications,
Min(sc.connected_at) AS firstReplication,
Max(sc.connected_at) AS lastReplication
FROM phoenix.synchro_connections sc
JOIN phoenix.users u
ON u.user_id = sc.user_id
WHERE Lower(sc.synchro_type) <> 'upload'
AND sc.size_in_bytes IS NOT NULL
GROUP BY sc.user_id,
u.short_name,
sc.synchro_type) AS t
WHERE short_name = 'BY060955'
ORDER BY replica_name ASC,
number_of_replications DESC
this is the result:
replica_name user_id short_name number_of_replications firstReplication LastReplication
All 22472 BY060955 836 2022-11-14 06:26:05.2415463 2022-12-08 10:25:17.4282712
All 22472 BY060955 2 2022-11-14 06:25:08.2385837 2022-11-16 11:55:41.0263526
Delta 22472 BY060955 836 2022-11-14 06:26:05.2415463 2022-12-08 10:25:17.4282712
Initial 22472 BY060955 2 2022-11-14 06:25:08.2385837 2022-11-16 11:55:41.0263526
I want for 'All' to be a single row (836+2 = 838) but'Delta' and 'Initial' to stay as they are

From the last query, remove the grouping by sc.synchro_type:
SELECT 'All' AS replica_name,
sc.user_id AS user_id,
u.short_name AS short_name,
Count(sc.user_id) AS number_of_replications,
Min(sc.connected_at) AS firstReplication,
Max(sc.connected_at) AS lastReplication
FROM phoenix.synchro_connections sc
JOIN phoenix.users u
ON u.user_id = sc.user_id
WHERE Lower(sc.synchro_type) <> 'upload'
AND sc.size_in_bytes IS NOT NULL
GROUP BY sc.user_id,
u.short_name
You should be able to calculated the above in a better way reading the rows from the tables only one. Then you can use UNPIVOT if you need the results in the same way:
SELECT sc.user_id AS user_id,
--
SUM(IIF(Lower(sc.synchro_type) = 'initial', 1, 0)) AS initial_number_of_replications,
MIN(IIF(Lower(sc.synchro_type) = 'initial', sc.connected_at, NULL)) AS initial_firstReplication,
MAX(IIF(Lower(sc.synchro_type) = 'initial', sc.connected_at, NULL)) AS initial_lastReplication,
--
SUM(IIF(Lower(sc.synchro_type) = 'delta', 1, 0)) AS delta_number_of_replications,
MIN(IIF(Lower(sc.synchro_type) = 'delta', sc.connected_at, NULL)) AS delta_firstReplication,
MAX(IIF(Lower(sc.synchro_type) = 'delta', sc.connected_at, NULL)) AS delta_lastReplication,
--
SUM(IIF(Lower(sc.synchro_type) <> 'upload', 1, 0)) AS ALL_number_of_replications,
MIN(IIF(Lower(sc.synchro_type) <> 'upload', sc.connected_at, NULL)) AS ALL_firstReplication,
MAX(IIF(Lower(sc.synchro_type) <> 'upload', sc.connected_at, NULL)) AS ALL_lastReplication
FROM phoenix.synchro_connections sc
INNER JOIN phoenix.users u
ON u.user_id = sc.user_id
WHERE Lower(sc.synchro_type) <> 'upload'
AND sc.size_in_bytes IS NOT NULL
AND u.short_name = 'BY060955'
GROUP BY sc.user_id

Related

How to select only unique values from this table based on criteria?

I want to select only the first record from each group. So basically I only want the data for first processing date column and don't want the rest of the date for each product.
My current code as below
SELECT
C.AccountID as ABN_ACC ,
C.ProductSymbol,
C.ProductShortName,
S.ReactorProduct AS REC_PROD,
C.CurrencyCode AS PROD_CCY,
C.CountryOfPayment AS PAYCONTRY,
C.DividendValueCur AS PAYCCY,
C.DividendValue AS DIV_AMNT,
CONCAT ((IIF (C.QuantitySettledNoTax_LS = 'S' ,(-1*C.QuantitySettledNoTax),C.QuantitySettledNoTax )),(IIF(C.QuantitySettledTax_LS = 'S',(-1*C.QuantitySettledTax),QuantitySettledTax))) AS DIVQTY ,
C.ExdividendDate AS EXDATE,
C.Recorddate AS RECDATE,
C.DividendPayDate AS PAYDATE
From "LiquidCDW". [Staging].[CA_CorporateActions] AS C
RIGHT JOIN "LiquidCDW".[Staging].[POS_SettledPositions] AS P ON C.Recorddate = P.ProcessingDate AND C.AccountID = p.AccountID AND C.ProductSymbol = P.ProductSymbol AND C.DividendValueCur = P.CurrencyCode
INNER JOIN "LiquidCDW".[Transformation].[Mapping_Product_ABNReactor] AS S ON C.ProductSymbol = S.ReactorProduct AND S.ValidTo IS NULL AND S.ProductType = 'E' AND c.DividendValueCur = S.Currency
where C.ExdividendDate >= '20210201'
ORDER by C.ProductSymbol , C.CurrencyCode
One approach uses ROW_NUMBER:
WITH cte AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY C.ProductSymbol ORDER BY processingDate) rn,
C.AccountID AS ABN_ACC,
C.ProductSymbol,
C.ProductShortName,
S.ReactorProduct AS REC_PROD,
C.CurrencyCode AS PROD_CCY,
C.CountryOfPayment AS PAYCONTRY,
C.DividendValueCur AS PAYCCY,
C.DividendValue AS DIV_AMNT,
CONCAT((IIF(C.QuantitySettledNoTax_LS = 'S',
(-1*C.QuantitySettledNoTax), C.QuantitySettledNoTax)),
(IIF(C.QuantitySettledTax_LS = 'S',
(-1*C.QuantitySettledTax),QuantitySettledTax))) AS DIVQTY,
C.ExdividendDate AS EXDATE,
C.Recorddate AS RECDATE,
C.DividendPayDate AS PAYDATE
FROM [LiquidCDW].[Staging].[CA_CorporateActions] AS C
RIGHT JOIN "LiquidCDW".[Staging].[POS_SettledPositions] AS P
ON C.Recorddate = P.ProcessingDate AND
C.AccountID = p.AccountID AND
C.ProductSymbol = P.ProductSymbol AND
C.DividendValueCur = P.CurrencyCode
INNER JOIN [LiquidCDW].[Transformation].[Mapping_Product_ABNReactor] AS S
ON C.ProductSymbol = S.ReactorProduct AND
S.ValidTo IS NULL AND
S.ProductType = 'E' AND
C.DividendValueCur = S.Currency
WHERE
C.ExdividendDate >= '20210201'
)
SELECT *
FROM cte
WHERE rn = 1
ORDER BY ProductSymbol, CurrencyCode;

Combine 3 UNIONed queries into one

I have the following which I would like to do without UNIONs so that the string split is only happening once.
I would also like the results to be in one line per MemberId showing all 3 counts rather than 3 rows.
SELECT MemberKey, 'login' as countType, count(MemberKey) as total FROM [dbo].[CA_MembersAudit]
WHERE isSuccess = 1 and MemberKey IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberKey
UNION
SELECT MemberId as MemberKey, 'articles' as countType, count(MemberId) as total FROM [dbo].[CA_Activities]
WHERE StateId = 'Opened' and MemberId IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberId
UNION
SELECT MemberId as MemberKey,'assessments' as countType, count(MemberId) as total FROM [dbo].[CA_Activities]
WHERE PercentageComplete is not null AND MemberId IN (SELECT value FROM STRING_SPLIT( #userList, ','))
Group By MemberId
UNION
Can anyone suggest how I should amend the queries into one to be able to do this?
You could use a subquery for each total:
select m.MemberKey,
(select count(*) from CA_MembersAudit ma where m.MemberKey = ma.MemberKey and ma.isSuccess = 1) as 'login_total',
(select count(*) from CA_Activities a where m.MemberKey = a.MemberId and a.stateId = 'Opened') as 'articles_total',
(select count(*) from CA_Activities a where m.MemberKey = a.MemberId and a.PercentageComplete is not null) as 'assessments_total'
from (select value as MemberKey from STRING_SPLIT('1,2,3,4', ',')) m
If your tables have a primary key, you could also do something like this:
select m.MemberKey,
count(distinct ma.Id) 'login_total',
count(distinct a1.Id) 'articles_total',
count(distinct a2.Id) 'assessments_total'
from (select value as MemberKey from STRING_SPLIT('1,2,3,4', ',')) m
left outer join CA_MembersAudit ma on m.MemberKey = ma.MemberKey and ma.isSuccess = 1
left outer join CA_Activities a1 on m.MemberKey = a1.MemberId and a1.stateId = 'Opened'
left outer join CA_Activities a2 on m.MemberKey = a2.MemberId and a2.PercentageComplete is not null
group by m.MemberKey
I believe you can use a CTE and then JOIN to each of the UNION participants.
WITH MemberList AS (
SELECT value AS Member
FROM STRING_SPLIT(#userList, ',')
)
SELECT
MemberKey
,'login' AS countType
,count(MemberKey) AS total
FROM [dbo].[CA_MembersAudit]
JOIN MemberList
ON MemberList.Member = CA_MembersAudit.MemberKey
WHERE isSuccess = 1
GROUP BY MemberKey
UNION
SELECT
MemberId AS MemberKey
,'articles' AS countType
,count(MemberId) AS total
FROM [dbo].[CA_Activities]
JOIN MemberList
ON MemberList.Member = CA_Activities.MemberId
WHERE StateId = 'Opened'
GROUP BY MemberId
UNION
SELECT
MemberId AS MemberKey
,'assessments' AS countType
,count(MemberId) AS total
FROM [dbo].[CA_Activities]
JOIN MemberList
ON MemberList.Member = CA_Activities.MemberId
WHERE PercentageComplete IS NOT NULL
GROUP BY MemberId;
try this :
With MemberList as (
SELECT value as ID FROM STRING_SPLIT( #userList, ',')
),
Activities as (
select f1.MemberId, sum(case when f1.StateId = 'Opened' then 1 else 0 end) as TotalOpened,
sum(case when f1.PercentageComplete is not null then 1 else 0 end) as TotalPercentageComplete
FROM [dbo].[CA_Activities] f1 inner join MemberList f2 on f1.MemberId=f2.ID
where f1.StateId = 'Opened' or f1.PercentageComplete is not null
group by f1.MemberId
),
MemberAudit as (
SELECT f1.MemberKey, count(*) as TotalSuccess
FROM [dbo].[CA_MembersAudit] f1 inner join MemberList f2 on f1.MemberKey=f2.ID
WHERE f1.isSuccess = 1
Group By f1.MemberKey
)
select f1.*, isnull(f2.TotalOpened, 0) as TotalOpened, isnull(f2.TotalPercentageComplete, 0) as TotalPercentageComplete, isnull(f3.TotalSuccess, 0) as TotalSuccess
from MemberList f1
left outer join Activities f2 on f1.ID=f2.MemberId
left outer join MemberAudit f3 on f1.ID=f3.MemberKey
other solution :
SELECT f1.value as ID, isnull(f2.TotalOpened, 0) as TotalOpened, isnull(f2.TotalPercentageComplete, 0) as TotalPercentageComplete, isnull(f3.TotalSuccess, 0) as TotalSuccess
FROM STRING_SPLIT( #userList, ',') f1
outer apply
(
select sum(case when f1.StateId = 'Opened' then 1 else 0 end) as TotalOpened,
sum(case when f1.PercentageComplete is not null then 1 else 0 end) as TotalPercentageComplete
FROM [dbo].[CA_Activities] f1
where (f1.StateId = 'Opened' or f1.PercentageComplete is not null) and f1.MemberId=f1.value
) f2
outer apply
(
SELECT count(*) as TotalSuccess FROM [dbo].[CA_MembersAudit] f1 WHERE f1.isSuccess = 1 and f1.MemberKey=f1.value
) f3

How to convert Mysqli NESTED JOIN query to Active record

I want to convert these mysql query to codeigniter Active Records
SELECT
u.user_id,
u.name as user_name,
u.branch,
b.name as branch_name,
r.*,
r3.valid_from as next_valid_from,
r3.valid_to as next_valid_to,
c.courses_name,
d.package_description as package_name,
t.from_time,
t.to_time,
u1.user_id as teacher_id,
u1.name as teacher_name,
u2.user_id as dietitian_id,
u2.name as dietitian_name
FROM
userdetail u
left join branch b on u.branch = b.id
left JOIN (
SELECT
*
FROM
rejoin
WHERE
CURDATE() BETWEEN valid_from
AND valid_to
) r on u.user_id = r.member_id
LEFT JOIN (
SELECT
r1.*
FROM
rejoin r1
join (
SELECT
member_id,
max(valid_from) as valid_from,
max(valid_to) as valid_to
FROM
rejoin
WHERE
CURDATE() < valid_from
) r2 on r1.member_id = r2.member_id
and r1.valid_from = r2.valid_from
) r3 on u.user_id = r3.member_id
LEFT join courses c on r.courses_id = c.courses_id
LEFT JOIN days_package d on r.days_type = d.package_name
left join timetable t on r.course_time_table_id = t.course_time_table_id
LEFT JOIN userdetail u1 on u.tech_assign = u1.user_id
left JOIN userdetail u2 on u.p_assinged_dit = u.user_id
WHERE
u.usr_acc_typ = 'p'
and u.status = 'Active'
Finally, I have an answer with the help of M.Hemant
$this->db->select('u.user_id,
u.name as user_name,
u.branch as branch_id,
b.name as branch_name,
r.courses_id,c.courses_name,
r.days_type,d.package_description as package_name,
r.valid_from,
r.valid_to,
r1.valid_from as next_valid_from,
r1.valid_to as next_valid_to,
r.course_time_table_id,
t.from_time,
t.to_time,
u1.user_id as teacher_id,
u1.name as teacher_name,
u2.user_id as dietitian_id,
u2.name as dietitian_name,
p.gender,
u.status')
->from('userdetail u')
->join('branch b','b.id = u.branch','LEFT')
->join("(SELECT * FROM rejoin WHERE '{$today}' BETWEEN valid_from AND valid_to ) as r ",'r.member_id = u.user_id','LEFT')
->join("(SELECT * FROM rejoin WHERE '{$today}' < valid_from AND valid_to ) as r1 ",'r1.member_id = u.user_id','LEFT')
->join('courses c','c.courses_id = r.courses_id','LEFT')
->join('days_package d', 'd.package_name = r.days_type','LEFT')
->join('timetable t','t.course_time_table_id =r.course_time_table_id','LEFT')
->join('personaldetail p','p.user_id = u.user_id','LEFT')
->join('userdetail u1','u1.user_id = u.tech_assign','LEFT')
->join('userdetail u2','u2.user_id = u.p_assinged_dit','LEFT')
->where('u.usr_acc_typ','p')
->where('u.status','Active')
->get();

In SQL , how do I create a query that will display this type of chart?

I'm looking for general pointers about how to do the following :
I have a chart that looks like this :
The following is my SQL so far , where I am using a WITH clause:
WITH WithSubquery1 AS (
SELECT AUTHORIZATION_STATUS AS "TOTAL AUTHO", COUNT(authorization_status) AS "Requisition Lines Count", LOCATION_CODE AS "Location",
imcb.SEGMENT1 AS "CATEGORY"
FROM
apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY
imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code Asc
) ,
WithSubquery2 AS
(
SELECT AUTHORIZATION_STATUS AS "APPROVED AUTHO", COUNT(authorization_status) AS "Requisition Lines Apprvd Count", LOCATION_CODE AS "Location",
imcb.SEGMENT1 AS "CATEGORY"
FROM
apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
and AUTHORIZATION_STATUS = 'APPROVED'
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY
imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code Asc
)
SELECT WithSubquery1."TOTAL AUTHO", WithSubquery1."Requisition Lines Count", WithSubquery2."APPROVED AUTHO", WithSubquery2."Requisition Lines Apprvd Count"
FROM
WithSubquery1 JOIN WithSubquery2
ON
WithSubquery1."Location" = WithSubquery2."Location"
The problem I'm having is that I'm not sure how to generate SQL so that it has the indentation shown, with the "Ship to" location having spaces underneath it for each of the 5 subcategories ("#Requisition Lines", "#Requisition Lines Approved" etc) . The results I get so far look like this :
This is confusing to read , and doesn't have the hanging -indent.
any tips appreciated, thanks !
Usually, I'd say you should worry about display issues in your front end and not in your SQL. However, you can employ this technique if you want to:
WITH d AS (
SELECT 'Canada' loc, 'APPROVED' status, 5 this_week FROM DUAL UNION ALL
SELECT 'Canada' loc, 'NOT APPROVED' status, 6 this_week FROM DUAL UNION ALL
SELECT 'New York' loc, 'APPROVED' status, 15 this_week FROM DUAL UNION ALL
SELECT 'Philadelphia' loc, 'APPROVED' status, 8 this_week FROM DUAL UNION ALL
SELECT 'Philadelphia' loc, 'NOT APPROVED' status, 2 this_week FROM DUAL )
SELECT case when row_number() over ( partition by loc order by status ) = 1 THEN loc else null end loc_display, status, this_week From d
-- make sure your order by matches your partition and order by
order by loc, status;

Show unique value for id, based on latest createby date

I am using the following SQL code to JOIN a few tables, but need to show unique values for the s.incidentid based on the latest s.createdate.
I know I need to use a Sub query with Maxdate, but I am not sure on the correct syntax.
This is my first query with multiple joins and I am struggling to get my head round it.
Here is my code:
SELECT
s.incidentid,
u.internalid as AssignedTo,
u.fullname as AssignedTo_FullName,
s.createby as AssignedBy,
u2.fullname as AssignedBy_FullName,
s.createdate as AssignedTime,
i.[description],
i.fix,
st.[description] as [Status],
(SELECT (CASE WHEN u.internalid = s.createby THEN 'Yes' ELSE 'No' END) as SelfAssigned),
d.d1,
d.d2,
d.d3,
d.d4,
d.d5
FROM dbo.IncidentServiceLevelAgreement s
JOIN dbo.UserAll u on u.userid = s.userid
JOIN dbo.UserAll u2 on u2.internalid = s.createby
JOIN dbo.IncidentAll i on s.incidentid = i.incidentid
JOIN dbo.[Status] st on i.statusid = st.statusid
JOIN dbo.flatdiagnosis d on i.actualdiagnosisid = d.diagnosisid
WHERE (s.groupId = '4954' and s.incidentServiceLevelAgreementTypeID = '9')
ORDER BY AssignedTime DESC
Any help greatly appreciated.
The easiest is to use a CTE and the ROW_NUMBER function:
WITH CTE AS
(
SELECT RN = ROW_NUMBER() OVER ( PARTITION BY incidentid
ORDER BY createdate DESC ),
s.Incidentid,
u.Internalid AS AssignedTo,
u.Fullname AS AssignedTo_FullName,
s.Createby AS AssignedBy,
u2.Fullname AS AssignedBy_FullName,
s.Createdate AS AssignedTime,
i.[Description],
i.Fix,
st.[Description] AS [Status],
SelfAssigned = CASE WHEN u.Internalid = s.Createby
THEN 'Yes' ELSE 'No' END,
d.D1,
d.D2,
d.D3,
d.D4,
d.D5
FROM dbo.Incidentservicelevelagreement s
JOIN dbo.Userall u
ON u.Userid = s.Userid
JOIN dbo.Userall u2
ON u2.Internalid = s.Createby
JOIN dbo.Incidentall i
ON s.Incidentid = i.Incidentid
JOIN dbo.[Status] st
ON i.Statusid = st.Statusid
JOIN dbo.Flatdiagnosis d
ON i.Actualdiagnosisid = d.Diagnosisid
WHERE ( s.Groupid = '4954'
AND s.Incidentservicelevelagreementtypeid = '9' )
)
SELECT * FROM CTE WHERE RN = 1
ORDER BY AssignedTime DESC
(instead of SELECT * list all columns explicitly, I didn't feel like it)