I need to add in an extra 'group by' field to the below code to group by Month in relation to the trade_date field. The code currently results in a table with column headers matching the 4 fields in the beginning 'select' statement. I need to add a 5th that uses the trade_date field to group by month, not day. Any thoughts?
select
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL
FROM
(
SELECT
a.transaction_id,
b.amount,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
g.instr_subtype_label,
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
timestamp_table.timeformated,
a.rate * a.basis_value AS dma_fee,
SUM(A.RATE * A.BASIS_VALUE) OVER () as DMA_FEE_TOTAL
FROM
repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d ON c.charge_type_id = d.charge_type_id
LEFT JOIN repldoadm.vw_ire_trade_transactions e ON a.transaction_id = e.trans_id
LEFT JOIN (
SELECT
to_char(create_ts, 'HH24:MI:SS') AS timeformated,
trans_id
FROM
repldoadm.vw_ire_trade_transactions
) timestamp_table ON ( a.transaction_id = timestamp_table.trans_id )
LEFT JOIN repldoadm.vw_ire_accounts f ON e.account_name = f.pb_account_name
LEFT JOIN stig_adm.instrument_universe g ON e.tradeable_instr_name = g.short_name
WHERE
timeformated >= '07:00:00'
AND timeformated <= '18:00:00'
AND fut_expiration_date >= add_months(trunc(sysdate), - 12)
AND trade_date = '02-AUG-21'
AND e.exchange_id = '30'
AND charge_group = 'EXECUTION_BROKER_CHARGES'
AND estimate_run = 'Late'
--AND transaction_id IN ( '791088074', '791309067' )
)
group by TRADEABLE_INSTR_NAME, TRADING_USERID, UNDERLYING_SYM_BLOOMBERG;
Group by TRUNC(trade_date, 'MM')
SELECT TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL,
TRUNC( trade_date, 'MM' ) AS trade_month
FROM (
<your huge sub-query>
)
group by
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM');
Your query would effectively be:
select TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM') AS trade_month
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL
FROM (
SELECT e.trading_userid,
e.tradeable_instr_name,
g.underlying_sym_bloomberg,
e.trade_date,
a.rate * a.basis_value AS dma_fee
FROM repldoadm.ire_estimate_trans_map a
INNER JOIN repldoadm.ire_charges_estimate b
ON a.estimate_id = b.estimate_id
INNER JOIN repldoadm.ire_charges_lu c
ON b.charge_id = c.charge_id
INNER JOIN repldoadm.ire_charge_types_lu d
ON c.charge_type_id = d.charge_type_id
INNER JOIN repldoadm.vw_ire_trade_transactions e
ON ( a.transaction_id = e.trans_id
AND TO_CHAR(e.create_ts, 'HH24:MI:SS') BETWEEN '07:00:00'
AND '18:00:00'
)
LEFT JOIN repldoadm.vw_ire_accounts f
ON e.account_name = f.pb_account_name
INNER JOIN stig_adm.instrument_universe g
ON e.tradeable_instr_name = g.short_name
WHERE g.fut_expiration_date >= add_months(trunc(sysdate), - 12)
AND e.trade_date = DATE '2021-08-02'
AND e.exchange_id = '30'
AND d.charge_group = 'EXECUTION_BROKER_CHARGES'
AND estimate_run = 'Late'
--AND transaction_id IN ( '791088074', '791309067' )
)
group by
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM');
Note: Because you are requiring non-NULL values in the WHERE clause your LEFT JOINs become INNER JOINs.
Note: You do not need to SELECT columns in the inner query that you are not using in the outer query.
Note: I do not know if you need to join repldoadm.vw_ire_accounts f as you do not appear to use it.
Related
I have posted the relevant part of my code below, up to and including the left join statement that I need a hand with. This statement to bring in a time column is returning multiple records in some cases. This is expected as there are several unique times per e.pb_trans_id. However I only want to bring back the record with the latest time. Is there a way I can single it out this way?
'''
SELECT
distinct a.transaction_id,
b.currency_id,
h.SIG_CURRENCY_CODE,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
a.rate * a.basis_value AS dma_fee,
SUM(A.RATE * A.BASIS_VALUE) OVER () as DMA_FEE_TOTAL
FROM
repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d ON c.charge_type_id = d.charge_type_id
LEFT JOIN repldoadm.vw_ire_trade_transactions e ON a.transaction_id = e.pb_trans_id
LEFT JOIN (
SELECT
to_char(create_ts, 'HH24:MI:SS') AS timeformated,
trans_id,
pb_trans_id
FROM
repldoadm.vw_ire_trade_transactions
) timestamp_table ON ( a.transaction_id = timestamp_table.trans_id or a.transaction_id = timestamp_table.pb_trans_id)
'''
I'm a little confused as to the fact that there are two different ids in vw_ire_trade_transactions, but generically, here's a way to do it if there were only one id. Can't give a full answer without learning more about the vw_ire_trade_transactions dataset.
LEFT JOIN (
SELECT
to_char(create_ts, 'HH24:MI:SS') AS timeformated,
pb_trans_id,
ROW_NUMBER() OVER (PARTITION BY pb_trans_id ORDER BY create_ts DESC) AS rn
FROM
repldoadm.vw_ire_trade_transactions
) timestamp_table
ON a.transaction_id = timestamp_table.pb_trans_id
WHERE timestamp_table.rn=1
I am building a table using multiple INNER JOIN queries on other tables and one of my queries is returning multiple matches (correctly based on how this function works) but I really just need to pull back one match, the first it hits in the comparison will do.
Below is my code. On the last INNER JOIN query there can be several a.transaction_id = e.pb_trans_id matches in the repldoadm.vw_ire_trade_transactions e table. Can I specify to just bring back 1 match?
'''
SELECT
distinct a.transaction_id,
b.currency_id,
h.SIG_CURRENCY_CODE,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
timestamp_table.timeformated,
a.rate * a.basis_value AS dma_fee,
SUM(A.RATE * A.BASIS_VALUE) OVER () as DMA_FEE_TOTAL
FROM
repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d ON c.charge_type_id = d.charge_type_id
LEFT JOIN repldoadm.vw_ire_trade_transactions e ON a.transaction_id = e.pb_trans_id --or a.transaction_id = e.PB_TRANS_ID
LEFT JOIN (
SELECT
to_char(create_ts, 'HH24:MI:SS') AS timeformated,
trans_id,
pb_trans_id
FROM
repldoadm.vw_ire_trade_transactions
) timestamp_table ON ( a.transaction_id = timestamp_table.trans_id or a.transaction_id = timestamp_table.pb_trans_id)
LEFT JOIN repldoadm.vw_ire_accounts f ON e.account_name = f.pb_account_name
LEFT JOIN stig_adm.instrument_universe g ON e.tradeable_instr_name = g.short_name
LEFT JOIN STIG_ADM.BBG_LU_CURRENCY h ON c.payment_currency_id = h.SIG_CURRENCY_ID
'''
You can use a lateral join with a limit clause for this. For a lateral outer join I suggest to use OUTER APPLY, because unlike with LEFT JOIN LATERAL you don't have to add a dummy ON clause to get this syntactically correct.
SELECT
distinct a.transaction_id,
b.currency_id,
h.SIG_CURRENCY_CODE,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
to_char(e.create_ts, 'HH24:MI:SS'),
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
-- timestamp_table.timeformated,
a.rate * a.basis_value AS dma_fee,
SUM(A.RATE * A.BASIS_VALUE) OVER () as DMA_FEE_TOTAL
FROM
repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d ON c.charge_type_id = d.charge_type_id
OUTER APPLY
(
SELECT *
FROM repldoadm.vw_ire_trade_transactions tt
WHERE tt.pb_trans_id = a.transaction_id
FETCH FIRST ROW ONLY
) e;
If you don't care which row to return, perhaps ROW_NUMBER analytic function might help. Your current query - with addition of the named function - would be used as a subquery (or a CTE, as in my example), while the "final" query would return rows whose RN = 1.
Something like this:
WITH temp AS
( SELECT DISTINCT a.transaction_id,
b.currency_id,
h.SIG_CURRENCY_CODE,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
TO_CHAR (e.create_ts, 'HH24:MI:SS'),
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
a.rate * a.basis_value AS dma_fee,
SUM (A.RATE * A.BASIS_VALUE) OVER () AS DMA_FEE_TOTAL,
-- this:
ROW_NUMBER () OVER (PARTITION BY e.pb_trans_id ORDER BY e.create_ts DESC) rn
FROM repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b
ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c
ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d
ON c.charge_type_id = d.charge_type_id
LEFT JOIN repldoadm.vw_ire_trade_transactions e
ON a.transaction_id = e.pb_trans_id
)
SELECT t.*
FROM temp t
WHERE t.rn = 1
I have built a table taking columns from several other tables that are all linked by one or another common columns. I now need to perform simple multiplication on 2 the data in 2 columns contained in the table I have built. I see examples of the syntax such as this:
SELECT name,
price*quantity AS total_price
FROM purchase;
however I don't know what to put in here for the 'FROM' table as I am performing this arithmetic on 2 columns from the table I have built which to my knowledge doesn't have a name (unless there is some sort of default name you can use for these tables we build? I am very new to SQL..).
Here is my code so far:
select A.*,
A.TRANSACTION_ID,
B.AMOUNT,
B.CHARGE_ID,
C.CHARGE_TYPE_ID,
D.CHARGE_GROUP,
E.EXCHANGE_ID,
E.TRADE_DATE,
timestamp_table.timeformated
FROM REPLDOADM.IRE_ESTIMATE_TRANS_MAP A
left join REPLDOADM.IRE_CHARGES_ESTIMATE B ON A.ESTIMATE_ID = B.ESTIMATE_ID
left join REPLDOADM.IRE_CHARGES_LU C ON B.CHARGE_ID = C.CHARGE_ID
left join REPLDOADM.ire_charge_types_lU D ON C.CHARGE_TYPE_ID = D.CHARGE_TYPE_ID
left join REPLDOADM.VW_IRE_TRADE_TRANSACTIONS E ON A.TRANSACTION_ID = E.TRANS_ID
left join (
select to_char(create_ts, 'HH24:MI:SS') as timeformated, TRANS_ID
from REPLDOADM.VW_IRE_TRADE_TRANSACTIONS) timestamp_table ON (A.TRANSACTION_ID =
timestamp_table.TRANS_ID)
On my output I have 2 columns called RATE and BASIS_TYPE which I need to muliply together on a row by row basis and get the output in a new column. These 2 columns were both taken from REPLDOADM.IRE_ESTIMATE_TRANS_MAP initially.
Any thoughts?
I think you simply need this -
select A.*,
A.TRANSACTION_ID,
B.AMOUNT,
B.CHARGE_ID,
C.CHARGE_TYPE_ID,
D.CHARGE_GROUP,
E.EXCHANGE_ID,
E.TRADE_DATE,
timestamp_table.timeformated,
A.RATE * A.BASIS_TYPE CALC_RATE
FROM REPLDOADM.IRE_ESTIMATE_TRANS_MAP A
left join REPLDOADM.IRE_CHARGES_ESTIMATE B ON A.ESTIMATE_ID = B.ESTIMATE_ID
left join REPLDOADM.IRE_CHARGES_LU C ON B.CHARGE_ID = C.CHARGE_ID
left join REPLDOADM.ire_charge_types_lU D ON C.CHARGE_TYPE_ID = D.CHARGE_TYPE_ID
left join REPLDOADM.VW_IRE_TRADE_TRANSACTIONS E ON A.TRANSACTION_ID = E.TRANS_ID
left join (
select to_char(create_ts, 'HH24:MI:SS') as timeformated, TRANS_ID
from REPLDOADM.VW_IRE_TRADE_TRANSACTIONS) timestamp_table ON (A.TRANSACTION_ID =
timestamp_table.TRANS_ID)
This big query below returns me 2860 records and its correct number. I'm getting. The thing is that I need to add to this query invoice lines and make the same thing as I did with sale_order_lines "sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) AS price_subtotal". I need to get the sum of price_subtotal of invoice lines.
so my first thought was to join tables like this.
JOIN sale_order_invoice_rel so_inv_rel on (so_inv_rel.order_id = s.id )
JOIN account_invoice inv on (inv.id = so_inv_rel.invoice_id and inv.state in ('open','paid'))
JOIN account_invoice_line ail on (inv.id = ail.invoice_id)
and then
sum(ail.price_subtotal / COALESCE(cr.rate, 1.0)) as price_subtotal
but after the first JOIN number of lines, I'm selecting is changing and even if I joins are done the numbers are way off basically I get 5x2860. So probably I need to make some subquery but at this point, I don't know how and asking for help.
WITH currency_rate AS (
SELECT r.currency_id,
COALESCE(r.company_id, c.id) AS company_id,
r.rate,
r.name AS date_start,
( SELECT r2.name
FROM res_currency_rate r2
WHERE r2.name > r.name AND r2.currency_id = r.currency_id AND (r2.company_id IS NULL OR r2.company_id = c.id)
ORDER BY r2.name
LIMIT 1) AS date_end
FROM res_currency_rate r
JOIN res_company c ON r.company_id IS NULL OR r.company_id = c.id
)
SELECT min(l.id) AS id,
l.product_id,
l.color_id,
l.product_size_id,
t.uom_id AS product_uom,
sum(l.product_uom_qty / u.factor * u2.factor) AS product_uom_qty,
sum(l.qty_delivered / u.factor * u2.factor) AS qty_delivered,
sum(l.qty_invoiced / u.factor * u2.factor) AS qty_invoiced,
sum(l.qty_to_invoice / u.factor * u2.factor) AS qty_to_invoice,
sum(l.price_total / COALESCE(cr.rate, 1.0)) AS price_total,
l.price_unit / COALESCE(cr3.rate, 1.0) AS price_total_by_cmp_curr,
sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) AS price_subtotal,
count(*) AS nbr,
s.date_order AS date,
s.state,
s.partner_id,
s.user_id,
s.company_id,
date_part('epoch'::text, avg(date_trunc('day'::text, s.date_order) - date_trunc('day'::text, s.create_date))) / (24 * 60 * 60)::numeric(16,2)::double precision AS delay,
t.categ_id,
s.pricelist_id,
s.project_id AS analytic_account_id,
s.team_id,
p.product_tmpl_id,
partner.country_id,
partner.commercial_partner_id
FROM sale_order_line l
JOIN sale_order s ON l.order_id = s.id
JOIN res_partner partner ON s.partner_id = partner.id
LEFT JOIN product_product p ON l.product_id = p.id
LEFT JOIN product_template t ON p.product_tmpl_id = t.id
LEFT JOIN product_uom u ON u.id = l.product_uom
LEFT JOIN product_uom u2 ON u2.id = t.uom_id
LEFT JOIN res_company rc ON rc.id = s.company_id
LEFT JOIN product_pricelist pp ON s.pricelist_id = pp.id
LEFT JOIN currency_rate cr ON cr.currency_id = pp.currency_id AND cr.company_id = s.company_id AND cr.date_start <= COALESCE(s.date_order::timestamp with time zone, now()) AND (cr.date_end IS NULL OR cr.date_end > COALESCE(s.date_order::timestamp with time zone, now()))
LEFT JOIN currency_rate cr3 ON cr.currency_id = rc.currency_id AND cr.company_id = s.company_id AND cr.date_start <= COALESCE(s.date_order::timestamp with time zone, now()) AND (cr.date_end IS NULL OR cr.date_end > COALESCE(s.date_order::timestamp with time zone, now()))
GROUP BY l.product_id, t.uom_id, t.categ_id, s.date_order, s.partner_id, s.user_id, s.state, s.company_id, s.pricelist_id, s.project_id, s.team_id, l.color_id, cr3.rate, l.price_unit, l.product_size_id, p.product_tmpl_id, partner.country_id, partner.commercial_partner_id;
You can add the part that could be in a subquery to the with statement you already have to avoid the increase in number of lines, like so:
WITH currency_rate AS (
SELECT r.currency_id,
COALESCE(r.company_id, c.id) AS company_id,
r.rate,
r.name AS date_start,
( SELECT r2.name
FROM res_currency_rate r2
WHERE r2.name > r.name AND r2.currency_id = r.currency_id AND (r2.company_id IS NULL OR r2.company_id = c.id)
ORDER BY r2.name
LIMIT 1) AS date_end
FROM res_currency_rate r
JOIN res_company c ON r.company_id IS NULL OR r.company_id = c.id
)
, order_line_subtotal AS(
SELECT so_inv_rel.order_id, sum(ail.price_subtotal) as price_subtotal
FROM sale_order_invoice_rel so_inv_rel
JOIN account_invoice inv on (inv.id = so_inv_rel.invoice_id and inv.state in ('open','paid'))
JOIN account_invoice_line ail on (inv.id = ail.invoice_id)
GROUP BY so_inv_rel.order_id )
SELECT min(l.id) AS id,
....
From there it should be straightforward to add to the query without increasing the number of rows (since from the joins you already have a row for each order before the aggregation / group by.
I have a query as below:
SELECT
cc.chain_desc as chain_desc
,cc.chain_id as chain_id
,COUNT(distinct t.trans_id) as TranCount
FROM TRANSACTION AS t
LEFT OUTER JOIN location AS l
ON t.location_id = l.location_id
LEFT OUTER JOIN trans_line AS tl
ON t.trans_id = tl.trans_id
LEFT OUTER JOIN contract as c
ON t.contract_id = c.contract_id
LEFT OUTER JOIN chain_desc as cc
ON l.chain_id = cc.chain_id
WHERE
t.loc_country = 'U'
AND c.issuer_id IN (156966,166203)
AND t.trans_date >= '2016-10-01 00:00'
and t.trans_date < '2016-10-31 00:00'
AND tl.cat NOT IN ('DEF','DEFD','DEFC')
GROUP BY cc.chain_desc, cc.chain_id
UNION
SELECT
'TOTAL'
,0
,COUNT(distinct t.trans_id)
FROM TRANSACTION AS t
LEFT OUTER JOIN location AS l
ON t.location_id = l.location_id
LEFT OUTER JOIN trans_line AS tl
ON t.trans_id = tl.trans_id
LEFT OUTER JOIN contract as c
ON t.contract_id = c.contract_id
LEFT OUTER JOIN chain_desc as cc
ON l.chain_id = cc.chain_id
WHERE
t.loc_country = 'U'
AND c.issuer_id IN (156966,166203)
AND t.trans_date >= '2016-10-01 00:00'
and t.trans_date < '2016-10-31 00:00'
AND tl.cat NOT IN ('DEF','DEFD','DEFC')
The above query when executed reurns the below result:
I need the result to be displayed as below:
The column "Chain_Id" is of "integer" type, how can I make that blank?.
you can simply select null
.....
UNION
SELECT
'TOTAL'
, NULL::INTEGER
,COUNT(distinct t.trans_id)
FROM TRANSACTION AS t
LEFT OUTER JOIN location AS l
ON t.location_id = l.location_id
LEFT OUTER JOIN trans_line AS tl
ON t.trans_id = tl.trans_id
LEFT OUTER JOIN contract as c
ON t.contract_id = c.contract_id
LEFT OUTER JOIN chain_desc as cc
ON l.chain_id = cc.chain_id
WHERE
t.loc_country = 'U'
AND c.issuer_id IN (156966,166203)
AND t.trans_date >= '2016-10-01 00:00'
and t.trans_date < '2016-10-31 00:00'
AND tl.cat NOT IN ('DEF','DEFD','DEFC')
because null is not a type you could try add above the first query
DEFINE test INT;
LET test = NULL;
......
SELECT
'TOTAL'
, test
,COUNT(distinct t.trans_id)
.....
Or like suggusted by #Jonathan Leffler use NULL::INTEGER or CAST(NULL AS INTEGER)
In Informix you can use NULL in the projection list, but the column must have a type. Since in Informix NULL does not have a type, you need to use a CAST.
SELECT NULL::INTEGER AS id FROM systables WHERE tabid = 1;
SELECT CAST(NULL AS INTEGER) AS id FROM systables WHERE tabid = 1;
You can check the answers to this other question (Informix: Select null problem).
You can check the IBM Knowledge Center (NULL Keyword).
One way is to convert to NULL:
(case when cc.chain_id <> 0 then cc.chain_id end) as chain_id
Another is to convert everything to a string:
(case when cc.chain_id <> 0 then cast(cc.chain_id as varchar(255)) else '' end) as chain_id