I am trying to iterate over a Temporary Table inside of a Function, where I want to make an Update on every row.
The Temporary Table should hold all the user ID's that are getting out of the query.
After that, for every Single User it should be checked, if the percentage of the transactions with attributes is smaller than 50% of all transactions.
In the end, the account field master_segments should be updated.
My Code looks like that:
CREATE OR REPLACE FUNCTION temptable()
RETURNS VARCHAR
AS $$
BEGIN
CREATE TEMP TABLE IF NOT EXISTS testTable AS
SELECT account.sfid, transactions.transactionNumber
FROM account
INNER JOIN transactions ON account.sfid =transactions.accountsfid
INNER JOIN transactionLineItems ON transactions.transactionNumber = transactionLineItems.transactionNumber
INNER JOIN products ON transactionLineItems.USIM = products.USIM
WHERE account.gender = '1' AND (transactions.transactionDate >= current_date - interval '730' day AND products.gender = 'female' AND products.agegroup = 'adult');
FOR j IN testTable.sfid LOOP
SELECT(
(SELECT COUNT(transactions.transactionNumber)
FROM transactions
INNER JOIN account ON account.sfid = transactions.accountsfid
INNER JOIN transactionLineItems ON transactions.transactionNumber = transactionLineItems.transactionNumber
INNER JOIN products ON transactionLineItems.USIM = products.USIM
WHERE products.gender = 'male' AND products.agegroup = 'adult' AND transactions.transactionDate >= current_date - interval '730' day)*1.0 /
(SELECT COUNT(transactions.transactionNumber)
FROM transactions
WHERE transactions.transactionDate >= current_date - interval '730' day)
) < 0.5;
UPDATE account
SET account.master_segments = 'Women' WHERE account.sfid = testTable.sfid;
END LOOP;
END;
$$ LANGUAGE plpgsql;
I am getting this message:
ERROR: syntax error at or near "testTable"
LINE 14: FOR j IN testTable.sfid LOOP
Does someone has a suggestion on this?
Thanks!
I assume what you try to do is:
UPDATE account
SET account.master_segments = 'Women'
FROM (
SELECT account.sfid, transactions.transactionNumber
FROM account
INNER JOIN transactions ON account.sfid =transactions.accountsfid
INNER JOIN transactionLineItems ON transactions.transactionNumber = transactionLineItems.transactionNumber
INNER JOIN products ON transactionLineItems.USIM = products.USIM
WHERE account.gender = '1' AND (transactions.transactionDate >= current_date - interval '730' day AND products.gender = 'female' AND products.agegroup = 'adult')
) testtable
WHERE account.sfid = testtable.sfid
You don't need a subquery and you don't need to repeat the account table for this logic:
UPDATE account a
SET master_segments = 'Women'
FROM transactions t INNER JOIN
transactionLineItems tli
ON t.transactionNumber = tli.transactionNumber AND
t.transactionDate >= current_date - interval '730' day INNER JOIN
products p
ON tli.USIM = p.USIM AND
p.gender = 'female' AND
p.agegroup = 'adult'
WHERE a.gender = '1' AND a.sfid = t.sfid;
I also introduced table aliases so the query is easier to write and to read.
Related
I have a stored procedure:
`SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [ebs].[DB_Task_ONEYCRPRaport]
--#startDate DATE,
--#endDate DATE
AS
BEGIN
SELECT DISTINCT
CAST(A.ExternalMerchantId as varchar) "Merchant_guid", -- ok
CAST(C.CreatedOn AS DATE) "Purchase_date", --ok
CAST(C.CreatedOn AS TIME) "Purchase_hour", --ok
C.ContractNo "Funding_reference",--ok
APP.OrderNo "External_reference", --ok
A.CustomerInternalId "Customer_external_code",--ok
CASE WHEN I.TotalAmountToPay = 0 THEN '-' ELSE '+' END "Total_amount_symbol",--ok
CASE WHEN I.TotalAmountToPay = 0 THEN I.TotalAmountToRecover ELSE I.TotalAmountToPay END "Total_amount"
from ebs.Account as A
JOIN ebs.FTOS_CB_Contract AS C ON A.Accountid = C.CustomerId
JOIN ebs.FTOS_CB_BankAccount AS BA ON BA.FTOS_CB_BankAccountid = C.MainBankAccountId
JOIN ebs.FTOS_CB_BankAccountOperation AS BAO ON BAO.BankAccountId = BA.FTOS_CB_BankAccountid
JOIN Ebs.FTOS_CMB_Currency AS CU ON CU.FTOS_CMB_Currencyid = C.CurrencyId
JOIN ebs.FTOS_TPM_Invoice AS I ON I.BankAccountId = BA.FTOS_CB_BankAccountid
JOIN ebs.FTOS_TPM_InvoiceDetail AS ID ON ID.InvoiceId = I.FTOS_TPM_Invoiceid
JOIN ebs.FTOS_BNKAP_Application AS APP ON APP.ContractId = ID.ContractId
JOIN ebs.FTOS_CB_Payment AS P ON I.FTOS_TPM_Invoiceid=P.InvoiceId
JOIN ebs.FTOS_BP_BankingProduct AS BP ON BP.FTOS_BP_BankingProductid=(SELECT CO.ProductId from ebs.FTOS_CB_Contract AS CO where CO.FTOS_CB_Contractid = ID.ContractId)
JOIN ebs.FTOS_TPM_PreInvoiceDetail AS PID ON PID.ContractId = C.FTOS_CB_Contractid
left JOIN ebs.FTOS_ONEY_ICE_Repayment as R ON P.PaymentNo = R.PaymentNo
left JOIN ebs.FTOS_ONEY_ICE_Repayment_Details AS RD ON RD.FTOS_ONEY_ICE_Repaymentid = R.FTOS_ONEY_ICE_Repaymentid -- detalii plati efectuate
left JOIN ebs.FTOS_ONEY_ICE_Libra_ReceivedPayments AS RP ON RP.FTOS_CB_Contractid = C.FTOS_CB_Contractid --and DATEPART(week, C.CreatedOn) = DATEPART(week, GETDATE()) take current week results
END`
I have another table where commissions are stored, the problem is I don't know how to select them in my stored procedure if they are on separate columns:
Here is the test query:
SELECT PID.*
FROM [ebs].[FTOS_TPM_PreInvoiceDetail] as PID
WHERE PID.Name = 'name'
Basically for this example I want those values 20 and 5 to be selected in my stored procedures as two different values, how can I achieve that?
I tried created another stored procedure, but I think is a very bad idea.
i'm experiencing really poor performance with this query, probably because of my poor experience with join.
The following query have to run on a DB2 database.
SELECT A.n_ann_ord
|| A.n_prg_ord AS numeroOrdine,
DATE(B.d_ins) AS dataInserimentoEGO,
DATE(A.d_ord) AS dataInserimento,
C.n_lot_prd AS lotto,
E.t_rag_soc AS consorzio,
D.t_rag_soc AS cliente,
b.c_obu_new AS obuid,
j.c_tar AS targa,
j.c_naz AS nazione,
C.c_pos AS postazione,
CASE
WHEN B.f_ric_obu_sat = 'S' THEN 'Satellitare'
ELSE 'Non Satellitare'
END AS tipoTitolo,
F.t_des AS statoOrdine,
CASE
WHEN (SELECT 1
FROM evda.tetsau_sos_tit_mul X
WHERE x.d_ord = a.d_ord
FETCH first ROW only) = 1 THEN 'S'
ELSE 'N'
END AS SOSTITUZIONE,
DATE(G.d_ape_pro) AS aperturaLotto,
DATE(G.d_chiu_pro) AS chiusuraLotto,
DATE(G.d_com_con) AS confezionamento,
DATE(C.d_spe_spe) AS spedizione,
C.c_ide_spe AS trackingNumber,
DATE(H.d_acq_con) AS consegna
FROM evda.tetsvi_ord A
JOIN evda.tets3t_int_srv B
ON A.c_ctp_cli = B.c_ctp_cli
AND A.d_ord = B.d_ord
JOIN evda.tetski_int_con_ord C
ON A.c_ctp_cli = C.c_ctp_cli
AND A.d_ord = C.d_ord
JOIN evda.tets25_ctp D
ON C.c_ctp_cli = D.c_ctp
JOIN evda.tets25_ctp E
ON C.c_ctp_con = E.c_ctp
JOIN evda.tetsvk_sta_ord F
ON A.c_sta_ord = F.c_sta_ord
JOIN evda.tetsvp_pre_tit I
ON a.c_ctp_cli = i.c_ctp_cli
AND a.d_ord = i.d_ord
JOIN evda.tetsmj_tit_pre_est J
ON a.c_ctp_cli = j.c_ctp_cli
AND a.d_ord = j.d_ord
AND b.n_prg_tit_pre = j.n_prg
LEFT JOIN evda.tetskk_lot_prd G
ON C.n_lot_prd = G.n_lot_prd
LEFT JOIN evda.tets3u_int_srv_spe H
ON B.d_ins = H.d_ins
WHERE DATE(a.d_ord) <= CURRENT_DATE
AND DATE(a.d_ord) >= CURRENT_DATE - 30 DAYS
GROUP BY A.n_ann_ord
|| A.n_prg_ord,
DATE(B.d_ins),
DATE(A.d_ord),
C.n_lot_prd,
E.t_rag_soc,
D.t_rag_soc,
b.c_obu_new,
j.c_tar,
j.c_naz,
C.c_pos,
B.f_ric_obu_sat,
F.t_des,
a.d_ord,
DATE(G.d_ape_pro),
DATE(G.d_chiu_pro),
DATE(G.d_com_con),
DATE(C.d_spe_spe),
C.c_ide_spe,
DATE(H.d_acq_con)
Avoid using functions on table columns in where clause. Also, check whether "group by" is necessary as suggested by #jarlh
If d_ord is timestamp column, change where clause to
a.d_ord < timestamp( CURRENT_DATE + 1 days)
AND a.d_ord >= timestamp( CURRENT_DATE - 30 DAYS )
I have one table transaction and another table transaction_item.
One transaction has multiple transaction_items.
I want to left join transaction_item if transaction_item.amount >= 2, else perform no join.
select ti.*
from transaction t
LEFT JOIN transaction_item ti on ti.unique_id = t.unique_id
AND ti.location_id = t.location_id
AND ti.transaction_date = t.transaction_date
AND ti.amount >= 2
where t.pos_transaction_id = 4220
and t.location_id = 1674
and t.transaction_date = '2020-05-08';
If I do it this way it is results in 15 rows in place of total 20 rows, because 20 rows are in transaction_item table corresponding to transaction_id 4220. But I want no join in this case because 5 rows in transaction_item have amount < 2.
Your description a bit confusing, but the title says:
"else perform no join"
So I think you want something this:
SELECT ti.*
FROM transaction t
LEFT JOIN transaction_item ti ON ti.unique_id = t.unique_id
AND ti.location_id = t.location_id
AND ti.transaction_date = t.transaction_date
AND NOT EXISTS (
SELECT FROM transaction_item tx
WHERE tx.unique_id = t.unique_id
AND tx.location_id = t.location_id
AND tx.transaction_date = t.transaction_date
AND tx.amount < 2) -- !
WHERE t.pos_transaction_id = 4220
AND t.location_id = 1674
AND t.transaction_date = '2020-05-08';
However, the LEFT JOIN in combination with only columns from the right table in the SELECT list is dubious at best. This way you get one row with all NULL values for every row in transaction that qualifies and has no matching rows in transaction_item or one or more matching rows with amount < 2. I doubt you want that.
Typically, you'll want to include columns from transaction in the SELECT list, or use an [INNER] JOIN instead.
So it could be:
SELECT ti.*
FROM transaction t
JOIN transaction_item ti USING (unique_id, location_id, transaction_date)
WHERE t.pos_transaction_id = 4220
AND t.location_id = 1674
AND t.transaction_date = '2020-05-08';
AND NOT EXISTS (
SELECT FROM transaction_item tx
WHERE tx.unique_id = t.unique_id
AND tx.location_id = t.location_id
AND tx.transaction_date = t.transaction_date
AND tx.amount < 2);
Then again, a table transaction_item would typically have a FK column transaction_id referencing transaction - in which case we can simplify
SELECT ti.*
FROM transaction t
JOIN transaction_item ti ON ti.transaction_id = t.transaction_id -- ?
WHERE t.pos_transaction_id = 4220
AND t.location_id = 1674
AND t.transaction_date = '2020-05-08';
AND NOT EXISTS (
SELECT FROM transaction_item tx
WHERE tx.transaction_id = t.transaction_id
AND tx.amount < 2);
You mentioned both pos_transaction_id and transaction_id, so I am guessing here ...
The major insight to take away from this: always show exact table definitions with any such question.
i have update query but when i execute the quesry it take a long time to execute until it success. i dont know whats wrong. i run in dbeaver is there anyway to execute the quesry without waiting too long ?
update m_deposit_account_term_and_preclosure
set last_accrued_amount = (select amount from acc_gl_journal_entry where entry_date = (select max(entry_date) from acc_gl_journal_entry) and entity_id = sa.id and type_enum = 2 and description = 'Accrual Deposit Interest Expense End Of Month')
from m_savings_account sa
where sa.id = m_deposit_account_term_and_preclosure.savings_account_id;
As written, the update is executing the subquery on a row by row basis. That's going to be very slow, indeed.
Changing to a set-based operation by joining your tables first will improve overall performance, but if you have a lot of rows to update, it could still take a long time. Adding a WHERE clause will help, but it's entirely dependent on your tables.
MySQL:
UPDATE
m_deposit_account_term_and_preclosure as da
JOIN
m_savings_account as sa
ON sa.id = da.savings_account_id
JOIN
(
SELECT
entity_id,
amount
FROM acc_gl_journal_entry
WHERE entry_date = (
SELECT max(entry_date)
FROM acc_gl_journal_entry
)
AND entity_id = sa.id
AND type_enum = 2
AND description = 'Accrual Deposit Interest Expense End Of Month'
) as amt
SET da.last_accrued_amount = amt.amount
WHERE da.last_accrued_amount <> amt.amount;
SQL Server:
UPDATE da
SET last_accrued_amount = amt.amount
FROM
m_deposit_account_term_and_preclosure as da
JOIN
m_savings_account as sa
ON sa.id = da.savings_account_id
JOIN
(
SELECT
entity_id,
amount
FROM acc_gl_journal_entry
WHERE entry_date = (
SELECT max(entry_date)
FROM acc_gl_journal_entry
)
AND entity_id = sa.id
AND type_enum = 2
AND description = 'Accrual Deposit Interest Expense End Of Month'
) as amt
WHERE da.last_accrued_amount <> amt.amount;
I'm doing a weight reporting and I have a problem. I use this query to know the enters of weight in our warehouse, but when there are no transactions in a date this date doesn't appears in the results.
SELECT erp.MKPF.BUDAT AS Data,
Sum( erp.MSEG.MENGE * erp.MARM.BRGEW ) as pes
From erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MKPF.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112) -1
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
GROUP BY erp.MKPF.BUDAT*
Now the results are like this:
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120723 9999999.7777
And i need this
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120722 0
20120723 999999.7777
Can somebody help me?
Use a table or a view to generate the date range of interest and let this drive the query. Then you outer join your results to this view. This can be done dynamically in the query. For example, in Oracle, you can use "connect by" to generate a series:
create table my_summary(the_day date, pes number);
insert into my_summary values(to_date('20120720', 'yyyymmdd'), 9999999.9999);
insert into my_summary values(to_date('20120721', 'yyyymmdd'), 9999999.8888);
insert into my_summary values(to_date('20120723', 'yyyymmdd'), 9999999.7777);
SELECT d.the_day, NVL(s.pes, 0) AS pes
FROM ( SELECT to_date('20120720', 'yyyymmdd') + level -1 AS the_day
FROM dual CONNECT BY level <= 4) d
LEFT OUTER JOIN my_summary s ON (d.the_day = s.the_day)
ORDER BY 1
THE_DAY PES
--------- ---
20-JUL-12 9999999.9999
21-JUL-12 9999999.8888
22-JUL-12 0
23-JUL-12 9999999.7777
Other rdbms have other methods to generate a series. This will require you to know the start date you want, and the number of records (in the example above 20120720 and 4).
Thanks to all, finally I did this and it works
SELECT
c.BUDAT AS DATA,
CASE When SAP.pes Is Null then '0'
ELSE SAP.pes
END
From
erp.YSD_CALENDAR as c LEFT JOIN
(SELECT
erp.MKPF.BUDAT,
Sum(
erp.MSEG.MENGE
* erp.MARM.BRGEW ) as pes
FROM
erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE
erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
and erp.MSEG.SHKZG = 'S'
GROUP BY erp.MKPF.BUDAT
) SAP ON SAP.BUDAT = c.BUDAT
WHERE
c.BUDAT >= '20120720'
and c.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY c.BUDAT, SAP.pes
ORDER BY c.BUDAT