DBT - use DBT modeling to insert rows in a table like date dimension table in Azure Synapse - insert-update

I need reference to inserting rows in a table using DBT models. Sample example that can be considered is a date dimension table, where we want to insert rows for next years.

dbt is built to handle the inserts for you since it generally works as a transformation layer on data already in your warehouse.
As an example of how to build a date dimension table, the gitlab data team have a public repo which includes an example of how to build that using the dbt-utils package macro for a date spine
The simplest version would just be:
date_dim.sql
WITH date_spine AS (
{{ dbt_utils.date_spine(
start_date="to_date('01/01/2000', 'mm/dd/yyyy')",
datepart="day",
end_date="to_date('12/01/2050', 'mm/dd/yyyy')"
)
}}
)
select * from date_spine
And the link to the gitlab example:
date_details_source.sql
WITH date_spine AS (
{{ dbt_utils.date_spine(
start_date="to_date('11/01/2009', 'mm/dd/yyyy')",
datepart="day",
end_date="dateadd(year, 40, current_date)"
)
}}
), calculated as (
SELECT
date_day,
date_day AS date_actual,
DAYNAME(date_day) AS day_name,
DATE_PART('month', date_day) AS month_actual,
DATE_PART('year', date_day) AS year_actual,
DATE_PART(quarter, date_day) AS quarter_actual,
DATE_PART(dayofweek, date_day) + 1 AS day_of_week,
CASE WHEN day_name = 'Sun' THEN date_day
ELSE DATEADD('day', -1, DATE_TRUNC('week', date_day)) END AS first_day_of_week,
CASE WHEN day_name = 'Sun' THEN WEEK(date_day) + 1
ELSE WEEK(date_day) END AS week_of_year_temp, --remove this column
CASE WHEN day_name = 'Sun' AND LEAD(week_of_year_temp) OVER (ORDER BY date_day) = '1'
THEN '1'
ELSE week_of_year_temp END AS week_of_year,
DATE_PART('day', date_day) AS day_of_month,
ROW_NUMBER() OVER (PARTITION BY year_actual, quarter_actual ORDER BY date_day) AS day_of_quarter,
ROW_NUMBER() OVER (PARTITION BY year_actual ORDER BY date_day) AS day_of_year,
CASE WHEN month_actual < 2
THEN year_actual
ELSE (year_actual+1) END AS fiscal_year,
CASE WHEN month_actual < 2 THEN '4'
WHEN month_actual < 5 THEN '1'
WHEN month_actual < 8 THEN '2'
WHEN month_actual < 11 THEN '3'
ELSE '4' END AS fiscal_quarter,
ROW_NUMBER() OVER (PARTITION BY fiscal_year, fiscal_quarter ORDER BY date_day) AS day_of_fiscal_quarter,
ROW_NUMBER() OVER (PARTITION BY fiscal_year ORDER BY date_day) AS day_of_fiscal_year,
TO_CHAR(date_day, 'MMMM') AS month_name,
TRUNC(date_day, 'Month') AS first_day_of_month,
LAST_VALUE(date_day) OVER (PARTITION BY year_actual, month_actual ORDER BY date_day) AS last_day_of_month,
FIRST_VALUE(date_day) OVER (PARTITION BY year_actual ORDER BY date_day) AS first_day_of_year,
LAST_VALUE(date_day) OVER (PARTITION BY year_actual ORDER BY date_day) AS last_day_of_year,
FIRST_VALUE(date_day) OVER (PARTITION BY year_actual, quarter_actual ORDER BY date_day) AS first_day_of_quarter,
LAST_VALUE(date_day) OVER (PARTITION BY year_actual, quarter_actual ORDER BY date_day) AS last_day_of_quarter,
FIRST_VALUE(date_day) OVER (PARTITION BY fiscal_year, fiscal_quarter ORDER BY date_day) AS first_day_of_fiscal_quarter,
LAST_VALUE(date_day) OVER (PARTITION BY fiscal_year, fiscal_quarter ORDER BY date_day) AS last_day_of_fiscal_quarter,
FIRST_VALUE(date_day) OVER (PARTITION BY fiscal_year ORDER BY date_day) AS first_day_of_fiscal_year,
LAST_VALUE(date_day) OVER (PARTITION BY fiscal_year ORDER BY date_day) AS last_day_of_fiscal_year,
DATEDIFF('week', first_day_of_fiscal_year, date_actual) +1 AS week_of_fiscal_year,
CASE WHEN EXTRACT('month', date_day) = 1 THEN 12
ELSE EXTRACT('month', date_day) - 1 END AS month_of_fiscal_year,
LAST_VALUE(date_day) OVER (PARTITION BY first_day_of_week ORDER BY date_day) AS last_day_of_week,
(year_actual || '-Q' || EXTRACT(QUARTER FROM date_day)) AS quarter_name,
(fiscal_year || '-' || DECODE(fiscal_quarter,
1, 'Q1',
2, 'Q2',
3, 'Q3',
4, 'Q4')) AS fiscal_quarter_name,
('FY' || SUBSTR(fiscal_quarter_name, 3, 7)) AS fiscal_quarter_name_fy,
DENSE_RANK() OVER (ORDER BY fiscal_quarter_name) AS fiscal_quarter_number_absolute,
fiscal_year || '-' || MONTHNAME(date_day) AS fiscal_month_name,
('FY' || SUBSTR(fiscal_month_name, 3, 8)) AS fiscal_month_name_fy,
(CASE WHEN MONTH(date_day) = 1 AND DAYOFMONTH(date_day) = 1 THEN 'New Year''s Day'
WHEN MONTH(date_day) = 12 AND DAYOFMONTH(date_day) = 25 THEN 'Christmas Day'
WHEN MONTH(date_day) = 12 AND DAYOFMONTH(date_day) = 26 THEN 'Boxing Day'
ELSE NULL END)::VARCHAR AS holiday_desc,
(CASE WHEN HOLIDAY_DESC IS NULL THEN 0
ELSE 1 END)::BOOLEAN AS is_holiday,
DATE_TRUNC('month', last_day_of_fiscal_quarter) AS last_month_of_fiscal_quarter,
IFF(DATE_TRUNC('month', last_day_of_fiscal_quarter) = date_actual, TRUE, FALSE) AS is_first_day_of_last_month_of_fiscal_quarter,
DATE_TRUNC('month', last_day_of_fiscal_year) AS last_month_of_fiscal_year,
IFF(DATE_TRUNC('month', last_day_of_fiscal_year) = date_actual, TRUE, FALSE) AS is_first_day_of_last_month_of_fiscal_year,
DATEADD('day',7,DATEADD('month',1,first_day_of_month)) AS snapshot_date_fpa,
DATEADD('day',44,DATEADD('month',1,first_day_of_month)) AS snapshot_date_billings
FROM date_spine
), final AS (
SELECT
date_day,
date_actual,
day_name,
month_actual,
year_actual,
quarter_actual,
day_of_week,
first_day_of_week,
week_of_year,
day_of_month,
day_of_quarter,
day_of_year,
fiscal_year,
fiscal_quarter,
day_of_fiscal_quarter,
day_of_fiscal_year,
month_name,
first_day_of_month,
last_day_of_month,
first_day_of_year,
last_day_of_year,
first_day_of_quarter,
last_day_of_quarter,
first_day_of_fiscal_quarter,
last_day_of_fiscal_quarter,
first_day_of_fiscal_year,
last_day_of_fiscal_year,
week_of_fiscal_year,
month_of_fiscal_year,
last_day_of_week,
quarter_name,
fiscal_quarter_name,
fiscal_quarter_name_fy,
fiscal_quarter_number_absolute,
fiscal_month_name,
fiscal_month_name_fy,
holiday_desc,
is_holiday,
last_month_of_fiscal_quarter,
is_first_day_of_last_month_of_fiscal_quarter,
last_month_of_fiscal_year,
is_first_day_of_last_month_of_fiscal_year,
snapshot_date_fpa,
snapshot_date_billings
FROM calculated
)
** I believe the gitlab team uses Snowflake so if you're using another platform, you may need to change a few functions **

Related

Snowflake - invalid identifier 'LEVEL'

When running this query, I'm getting an error in Snowflake: invalid identifier 'LEVEL'
Also, I had some help putting parts of the query together, and I'm confused by origination of reference to 'Q'. In the two 'from' clauses in the query, I don't understand where Q is pulling from - I don't have a table called 'Q' to pull from.
WITH Q AS (SELECT LEVEL Q_LEVEL FROM DUAL A CONNECT BY PRIOR LEVEL <= 36),
Q1 AS (
select
Q.Q_LEVEL Q_LEVEL
, v_dept_history_adj.associate_id,
v_dept_history_adj.home_department_code,
v_dept_history_adj.position_effective_date
, max(position_effective_date)
OVER(PARTITION BY v_dept_history_adj.associate_id) AS most_recent_record
from datawarehouse.srctable, Q
where v_dept_history_adj.position_effective_date <=
last_day(date_from_parts(year(current_date()),
month(current_date())-Q.Q_LEVEL,1),month))
select
associate_id
, position_effective_date
, home_department_code,
most_recent_record
, (last_day(date_from_parts(year(current_date())
,month(current_date())-Q_LEVEL,1),month)) AS month
FROM Q1
where position_effective_date = most_recent_record
order by month desc, position_effective_date desc
So in Oracle
SELECT LEVEL
FROM DUAL A
CONNECT BY PRIOR LEVEL <= 36
would give the rows 1 -> 36, in Snowflake need to use:
select row_number() over(order by null) as q_level
from table(generator(ROWCOUNT=>36));
last_day(date_from_parts(year(current_date()),
month(current_date())-Q.Q_LEVEL,1),month)
is the same as:
last_day(dateadd(month, -q.q_level, CURRENT_DATE), month)
at which point that should be moved into the Q CTE for read ability:
WITH Q AS (
select
row_number() over(order by null) as q_level,
last_day(dateadd(month, -q_level, CURRENT_DATE), month) as last_day_month
from table(generator(ROWCOUNT=>36))
), Q1 AS (
select
q.last_day_month
,v_dept_history_adj.associate_id
,v_dept_history_adj.home_department_code
,v_dept_history_adj.position_effective_date
,max(position_effective_date) OVER (PARTITION BY v_dept_history_adj.associate_id) AS most_recent_record
from datawarehouse.srctable
join Q
on v_dept_history_adj.position_effective_date <= q.last_day_month
)
select
associate_id
,position_effective_date
,home_department_code
,most_recent_record
,last_day_month AS month
FROM Q1
where position_effective_date = most_recent_record
order by month desc, position_effective_date desc
So in the question, it was asked "where does Q come from" Q is the first of the CTE's or Common Table Expression, with the the two blocks of
WITH cte_name (
<valid sql selection>
)
The above SQL from logical perspective could be as:
with cte_q as (
select
row_number() over(order by null) as q_level,
last_day(dateadd(month, -q_level, CURRENT_DATE), month) as last_day_month
from table(generator(ROWCOUNT=>36))
), cte_q1 as (
select
q.last_day_month
,v_dept_history_adj.associate_id
,v_dept_history_adj.home_department_code
,v_dept_history_adj.position_effective_date
,max(position_effective_date) over(partition by v_dept_history_adj.associate_id) AS most_recent_record
from datawarehouse.srctable
join cte_q
on v_dept_history_adj.position_effective_date <= q.last_day_month
)
select
associate_id
,position_effective_date
,home_department_code
,most_recent_record
,last_day_month AS month
from cte_q1
where position_effective_date = most_recent_record
order by month desc, position_effective_date desc
OR cte_q could be just a sub-query:
with cte_q1 as (
select
q.last_day_month
,v_dept_history_adj.associate_id
,v_dept_history_adj.home_department_code
,v_dept_history_adj.position_effective_date
,max(position_effective_date) over(partition by v_dept_history_adj.associate_id) AS most_recent_record
from datawarehouse.srctable
join (
select
row_number() over(order by null) as q_level,
last_day(dateadd(month, -q_level, CURRENT_DATE), month) as last_day_month
from table(generator(ROWCOUNT=>36))
) as q
on v_dept_history_adj.position_effective_date <= q.last_day_month
)
select
associate_id
,position_effective_date
,home_department_code
,most_recent_record
,last_day_month AS month
from cte_q1
where position_effective_date = most_recent_record
order by month desc, position_effective_date desc
and then the cte_q1 can also be just a sub-query, but the "main" query is just filtering results, so that can be pushed into a QUALIFY clause:
select
,v_dept_history_adj.associate_id
,v_dept_history_adj.position_effective_date
,v_dept_history_adj.home_department_code
,max(position_effective_date) over(partition by v_dept_history_adj.associate_id) AS most_recent_record
q.last_day_month as month
from datawarehouse.srctable
join (
select
row_number() over(order by null) as q_level,
last_day(dateadd(month, -q_level, CURRENT_DATE), month) as last_day_month
from table(generator(ROWCOUNT=>36))
) as q
on v_dept_history_adj.position_effective_date <= q.last_day_month
qualify position_effective_date = most_recent_record
order by month desc, position_effective_date desc
The major problem I see is that v_dept_history_adj seems like a view name, but it does not appear in the original tables/cte list, so I am not sure what the real code is really doing.

Computing session start and end using SQL window functions

I've a table of game logs containing a handDate, like this:
ID
handDate
1
2019-06-30 16:14:02.000
2
2019-07-12 06:18:02.000
3
...
I'd like to compute game sessions from this table (start and end), given that:
A new session is considered if there is no activity since 1 hour.
a session can exist across 2 days
So I'd like results like this:
day
session_start
sesssion_end
2019-06-30
2019-06-15 16:14:02.000
2019-06-15 16:54:02.000
2019-07-02
2019-07-02 16:18:02.000
2019-07-02 17:18:02.000
2019-07-02
2019-07-02 23:18:02.000
2019-07-03 03:18:02.000
2019-07-03
2019-07-03 06:18:02.000
2019-07-03 08:28:02.000
Currently I'm playing with the following code, but cannot achieve what I want:
SELECT *
FROM (
SELECT *,
strftime( '%s', handDate) - strftime( '%s', prev_event) AS inactivity
FROM (
SELECT handDate,
date( handDate) as day,
FIRST_VALUE( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate) AS first_event,
MIN(handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate),
MAX(handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate),
LAG( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS prev_event,
LEAD( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate) AS next_event
FROM hands
) last
) final
I'm using SQLite.
I found the following solution:
SELECT day,
sessionId,
MIN(handDate) as sessionStart,
MAX(handDate) as sessionEnd
FROM(
SELECT day,
handDate,
sum(is_new_session) over (
order by handDate rows between unbounded preceding and current row
) as sessionId
FROM (
SELECT *,
CASE
WHEN prev_event IS NULL
OR strftime('%s', handDate) - strftime('%s', prev_event) > 3600 THEN true
ELSE false
END AS is_new_session
FROM (
SELECT handDate,
date(handDate) as day,
LAG(handDate) OVER (
PARTITION BY date(handDate)
ORDER BY handDate RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS prev_event
FROM hands
)
)
)
GROUP BY sessionId
DROP TABLE IF EXISTS hands;
CREATE TABLE hands(handDate TIMESTAMP);
INSERT INTO hands(handDate)
VALUES ('2021-10-29 10:30:00')
, ('2021-10-29 11:35:00')
, ('2021-10-29 11:36:00')
, ('2021-10-29 11:37:00')
, ('2021-10-29 12:38:00')
, ('2021-10-29 12:39:00')
, ('2021-10-29 12:39:10')
;
SELECT start_period, end_period
FROM (
SELECT is_start, handDate AS start_period
, CASE WHEN is_start AND is_end THEN handDate
ELSE LEAD(handDate) OVER (ORDER BY handDate)
END AS END_period
FROM (
SELECT *
FROM (
SELECT *
,CASE WHEN (event-prev_event) * 1440.0 > 60 OR prev_event IS NULL THEN true ELSE FALSE END AS is_start
,CASE WHEN (next_event-event) * 1440.0 > 60 OR next_event IS NULL THEN true ELSE FALSE END AS is_end
FROM (
SELECT handDate
, juliANDay(handDate) event
, juliANDay(LAG(handDate) OVER (ORDER BY handDate)) AS prev_event
, juliANDay(LEAD(handDate) OVER (ORDER BY handDate)) AS next_event
FROM hands
) t
) t
WHERE is_start OR is_end
)t
)t
WHERE is_start

Finding least and highest month revenue

I was having a problem for organizing a table where shows me
the month with the highest revenue and the lowest order by revenue
all the information is in the same table (Ordertable)
So I have orderdate and orderfinalprice.
select orderdate as MonthsSales, Highestrevenue, Lowestrevenue
from
(select months
, max (orderfinalprice) as Highestrevenue, min (orderfinalprice) as Lowestrevenue
From hologicOrder_T)
order by monthsales;
What's missing is the grouping by month based on orderdate.
select orderdate as MonthsSales, Highestrevenue, Lowestrevenue
from
(select to_char(orderdate, 'Month') orderdate, max(orderfinalprice) as Highestrevenue
, min (orderfinalprice) as Lowestrevenue
from hologicOrder_T
group by to_char(orderdate, 'Month'))
order by monthsales;
As far as I understood your problem, you want two months data, one with highest revenue and one with lowest revenue.
You can get it by following:
Select max(case when minrn = 1 then month_ end) lowestrevenue_month,
max(case when minrn = 1 then totalrevenue end) lowestrevenue,
max(case when maxrn = 1 then month_ end) highestrevenue_month,
max(case when maxrn = 1 then totalrevenue end) highestrevenue
From
(Select trunc(orderdate, 'month') month_,
Sum(orderfinalprice) as totalrevenue,
Row_nuumber() over (partition by trunc(orderdate, 'month') order by Sum(orderfinalprice)) as minrn,
Row_nuumber() over (partition by trunc(orderdate, 'month') order by Sum(orderfinalprice) desc) as maxrn
From hologicOrder_T
Group by trunc(orderdate, 'month') )
Where 1 in (minrn, maxrn);
You should not use to_char(orderdate, 'Month') because it will be same for the month regardless of its year.
In output, highestrevenue_month and lowestrevenue_month will be first date of the month, you can format it accordingly using to_char.
Cheers!!

How to combine two different queries to get one output

I have created the below two queries to see changes within table per_assignments and per_supervisor for columns locat_id,org_id, mng_id.
with asg_loc_dep as (
select person_id,
prev_start_dt,
start_dt,
loc_old,
loc_new,
org_new,
org_old
from (
select person_id,
locat_id loc_new,
org_id org_new,
start_dt,
lag(locat_id) over (partition by person_id order by start_dt) loc_old,
lag(org_id) over (partition by person_id order by start_dt) org_old,
lag(start_dt) over (partition by person_id order by start_dt) prev_start_dt,
case start_dt when 1 + lag(end_dt) over (partition by person_id order by start_dt)
then 1 end flag
from per_assignments
)
where flag = 1
and (loc_new <> loc_old or org_new <> org_old)
)
with asg_asg as (
select person_id,
prev_start_dt,
start_dt,
new_mgr,
mngid_old
from (
select person_id,
mng_id new_mgr,
start_dt,
lag(mng_id) over (partition by assignment_id order by start_dt) mngid_old,
lag(start_dt) over (partition by assignment_id order by start_dt) prev_start_dt,
case start_dt when 1 + lag(end_dt) over (partition by assignment_id order by start_dt)
then 1 end flag
from per_supervisor
)
where flag = 1
and (mngid_old<>new_mgr)
)
I am getting the right results individually, is there a way to combine these two queries into one to get the below output structure :
person_id prev_start_dt start_dt loc_old loc_new org_new org_old mngid_old new_mgr
the common link between both these queries is the person_id. if i use union, what will i pass for the left out columns, also if for the same date -prev_start_dt and start_dt there is a change in loc_new and new_mgr, then it should come in 1 row. with union it will come in 2 rows.
sample fiddle in only the 1st query
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=a3b74f9c4f8371ad23bbf53dcbe41f67
WITH loc_dep AS
(
SELECT person_id,
prev_start_dt,
start_dt,
--assignment_id,
loc_old,
loc_new,
org_old,
org_new
FROM (
SELECT person_id,
assignment_id,
location_id loc_new,
organization_id org_new,
effective_start_date start_dt,
Lag(location_id) OVER (partition BY person_id ORDER BY effective_start_date) loc_old,
Lag(organization_id) OVER (partition BY person_id ORDER BY effective_start_date) org_old,
Lag(effective_start_date) OVER (partition BY person_id ORDER BY effective_start_date) prev_start_dt,
CASE effective_start_date
WHEN 1 + Lag(effective_end_date) OVER (partition BY person_id ORDER BY effective_start_date) THEN 1
END flag
FROM per_all_assignments_m paam
WHERE paam.person_id = '300000010518043'
AND paam.system_person_type = 'EMP'
AND paam.assignment_status_type = 'ACTIVE'
AND paam.assignment_type = 'E' )
WHERE flag = 1
AND (
loc_new <> loc_old
OR org_new <> org_old)) ,
with mgr_compare AS
(
SELECT DISTINCT person_id,
prev_start_dt,
start_dt,
mngr_new,
mngr_old
FROM (
SELECT person_id,
manager_id mngr_new,
effective_start_date start_dt,
effective_end_date end_date,
lag(manager_id) OVER ( partition BY assignment_id ORDER BY effective_start_date) mngr_old,
lag(effective_start_date) OVER ( partition BY assignment_id ORDER BY effective_start_date) prev_start_dt,
CASE effective_start_date
WHEN 1 + lag(effective_end_date) OVER (partition BY assignment_id ORDER BY effective_start_date) THEN 1
END flag
FROM per_assignment_supervisors_f pasf
WHERE pasf.person_id = '300000010518043')
WHERE flag = 1
AND (
mngr_new <> mngr_old ))
SELECT mgr_compare.person_id
FROM mgr_compare,
loc_dep
WHERE loc_dep.person_id = mgr_compare.person_id
You could put both CTEs in the same query, and then join the results on person_id:
with
asg_loc_dep as (
select
person_id,
prev_start_dt,
start_dt,
loc_old,
loc_new,
org_new,
org_old
from ( ... )
where ...
),
asg_asg as (
select
person_id,
prev_start_dt,
start_dt,
new_mgr,
mngid_old
from (...)
where ...
)
select
l.person_id,
l.prev_start_dt,
l.start_dt,
l.loc_old,
l.loc_new,
l.org_new,
l.org_old,
a.mngid_old,
a.new_mgr
from asg_loc_dep l
inner join asg_asg a on a.person_id = l.person_id

Separate SELECT into multiple columns by WHERE condition without creating multiple rows caused by adding to GROUP BY

I'm trying to split SUM( trs_amt ) and SELECT it into 'trs_sum' column when trs_trust_code is either 1 or 2, and into an 'interest' column when trs_trust_code = 9. I cant seem to figure out how to do it without creating an extra row when adding trs_trust_code to the GROUP BY. I have tried a CASE in SELECT, a CASE in GROUP BY, subqueries
SELECT
trs_desk,
dsk_name,
DATEPART( YEAR, DATEADD( DAY, trs_trx_date, '1600-12-31' ) ) as 'year',
DATEPART( MONTH, DATEADD( DAY, trs_trx_date, '1600-12-31' ) ) as 'month',
COUNT( DISTINCT trs_amt ) AS 'trs_count',
SUM( trs_amt ) AS 'trs_sum',
SUM( trs_comm_amt ) AS 'trs_comm_sum'
FROM cds.trs
JOIN cds.dsk on dsk_code = trs_desk
WHERE trs_desk IN ( 'ACE' )
AND trs_trust_code IN ('1','2','9')
GROUP BY trs_desk, year, month, dsk_name
ORDER BY trs_desk ASC, year DESC, month DESC
Please use the expression case when trs_trust_code = 9 then trs_amt else 0 end in the sum. For example like this:
SELECT
trs_desk,
dsk_name,
DATEPART( YEAR, DATEADD( DAY, trs_trx_date, '1600-12-31' ) ) as 'year',
DATEPART( MONTH, DATEADD( DAY, trs_trx_date, '1600-12-31' ) ) as 'month',
COUNT( DISTINCT trs_amt ) AS 'trs_count',
SUM( case when trs_trust_code = 1 or trs_trust_code = 2 then trs_amt else 0 end ) AS 'trs_sum',
SUM( case when trs_trust_code = 9 then trs_amt else 0 end ) AS 'interest',
SUM( trs_comm_amt ) AS 'trs_comm_sum'
FROM cds.trs
JOIN cds.dsk on dsk_code = trs_desk
WHERE trs_desk IN ( 'ACE' )
AND trs_trust_code IN ('1','2','9')
GROUP BY trs_desk, year, month, dsk_name
ORDER BY trs_desk ASC, year DESC, month DESC