I have the following function that handles a trigger on insert or update:
CREATE OR REPLACE FUNCTION ticketChangeFunc() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO dw.FactSalesHeader (DateKey, LocationKey, EmployeeKey, AppointmentTypeKey, TicketStatusTypeKey, TicketID,TotalAmount, IsNewPatient, IsActive)
SELECT d.date_key, COALESCE(l.LocationKey, 0), COALESCE(e.EmployeeKey, 0), COALESCE(a.AppointmentTypeKey, 0), COALESCE(ts.TicketStatusTypeKey, 0), NEW.ticket_id,
NEW.total_amount, NEW.is_new_patient, NEW.is_active
FROM db1.tickets t
JOIN dw.DimDate d on t.ticket_date = d.db_date
LEFT JOIN dw.DimLocation l on NEW.location_id = l.LocationID
LEFT JOIN dw.DimEmployee e on NEW.counselor_id = e.EmployeeID
LEFT JOIN dw.DimAppointmentType a on NEW.office_visit_ind = a.AppointmentTypeFlagAttribute
LEFT JOIN dw.DimTicketStatus ts on NEW.ticket2_status = ts.TicketStatusTypeID
ON CONFLICT (TicketID)
DO UPDATE
SET DateKey = d.date_key,
LocationKey = COALESCE(l.LocationKey, 0),
EmployeeKey = COALESCE(e.EmployeeKey, 0),
AppointmentTypeKey = COALESCE(a.AppointmentTypeKey, 0),
TicketStatusTypeKey = COALESCE(ts.TicketStatusTypeKey, 0),
TotalAmount = NEW.total_amount,
IsNewPatient = NEW.is_new_patient,
IsActive = NEW.is_active;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
I get the error: missing FROM-clause entry for table "d"
I thought maybe it was somehow related to the db1.tickets table that I'm not technically using in the query. I've tried taking out that bit and just doing FROM dw.DimDate with WHERE d.date_key = NEW.ticket_date, and that gives the same error.
There are a lot of these types of questions on SO, but I haven't found one that addresses this particular scenario, as I feel like it has something to do with it being inside of this trigger function.
The function gets called from this:
CREATE TRIGGER trg_tickets AFTER INSERT OR UPDATE ON db1.tickets
FOR EACH ROW EXECUTE PROCEDURE ticketChangeFunc();
I'm also wondering if using the ON CONFLICT UPDATE clause updates every row when it finds a match regardless of whether the values differ? Is there a performance impact to this, and if so, is there a way to check for equality of each field and do nothing if there are no differences?
For those who may happen to run into this in the future, the solution for me was to add a conditional to the function and handle inserts separately from updates:
CREATE OR REPLACE FUNCTION ticketChangeFunc() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO dw.FactSalesHeader (DateKey, LocationKey, EmployeeKey, AppointmentTypeKey, TicketStatusTypeKey, TicketID, TotalAmount, IsNewPatient, IsActive)
SELECT d.date_key, COALESCE(l.LocationKey, 0), COALESCE(e.EmployeeKey, 0), COALESCE(a.AppointmentTypeKey, 0), COALESCE(ts.TicketStatusTypeKey, 0), NEW.ticket_id,
NEW.total_amount, NEW.is_new_patient, NEW.is_active
FROM db1.tickets t
JOIN dw.DimDate d ON NEW.ticket_date = d.db_date
LEFT JOIN dw.DimLocation l ON NEW.location_id = l.LocationID
LEFT JOIN dw.DimEmployee e ON NEW.counselor_id = e.EmployeeID
LEFT JOIN dw.DimAppointmentType a ON NEW.office_visit_ind = a.AppointmentTypeFlagAttribute
LEFT JOIN dw.DimTicketStatus ts ON NEW.ticket2_status = ts.TicketStatusTypeID;
ELSE
UPDATE dw.FactSalesHeader
SET DateKey = CAST(TO_CHAR(NEW.ticket_date, 'YYYYMMDD') as integer),
LocationKey = COALESCE(l.LocationKey, 0),
EmployeeKey = COALESCE(e.EmployeeKey, 0),
AppointmentTypeKey = COALESCE(a.AppointmentTypeKey, 0),
TicketStatusTypeKey = COALESCE(ts.TicketStatusTypeKey, 0),
TotalAmount = NEW.total_amount,
IsNewPatient = NEW.is_new_patient,
IsActive = NEW.is_active
FROM dw.FactSalesHeader hdr
LEFT JOIN dw.DimLocation l ON NEW.location_id = l.LocationID
LEFT JOIN dw.DimEmployee e ON NEW.counselor_id = e.EmployeeID
LEFT JOIN dw.DimAppointmentType a ON NEW.office_visit_ind = a.AppointmentTypeFlagAttribute
LEFT JOIN dw.DimTicketStatus ts ON NEW.ticket2_status = ts.TicketStatusTypeID
WHERE hdr.TicketID = NEW.ticket_id;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Related
I want to create a function to return an array of multiple elements, the query work perfect but I can't execute as function because I'm getting error always, this is my function:
CREATE OR REPLACE FUNCTION public.buscarexamen(visit anyelement)
RETURNS anyelement
LANGUAGE plpgsql
AS $function$
BEGIN
return array(SELECT fn_folio_paciente(vi.clave_unilabor, vi.fecha, vi.consec) AS folio_paciente,
vi.cve_visita, gp.nombre AS nombre_grupo, gp.cve_grupo,
--
vp.cve_visita_prueba, p.cve_prueba, p.nombre AS nombre_prueba, me.nombre AS nombre_metodo,
--
gcf.visible AS visible_grupo,
cf.cve_grupo_campo_formato, gc.nombre_grupo_campo AS grupo_parametro, cf.nombre AS nombre_parametro,
cf.orden, cf.tipo_dato, cf.solo_lectura AS tipo_titulo,
cf.cve_seccion_padre, cf.tiene_elementos_seccion, cf.observacion AS observacion_parametro,
--
pr.cve_prueba_resultado, pr.tipo_formato_prueba AS tipo_formato, pr.cantidad_resultado AS cantidad_parametro,
pr.observaciones AS observacion_analista, pr.observaciones_prueba,
CASE
WHEN (TRIM(pr.observaciones) <> '') OR (TRIM(pr.observaciones_prueba) <> '') THEN 1
ELSE 0 END AS prueba_tiene_observacion,
--
rc.cve_resultado_campo, rc.resultado, rc.observacion AS observacion_resultado, rc.signo, rc.decimales, cf.xleft as cursiva,
vr.valor_referencia_min, vr.valor_referencia_max, un.nombre AS nombre_unidad,
cf.tiene_valores_referencia
FROM visitas vi
JOIN corporativo.unilabor_unidades uu ON (vi.cve_unilabor_unidad = uu.cve_unilabor_unidad)
JOIN visita_pruebas vp ON (vi.cve_visita = vp.cve_visita)
JOIN prueba_resultados pr ON (vp.cve_visita_prueba = pr.cve_visita_prueba)
JOIN prueba_metodo pm ON (pr.cve_prueba_metodo = pm.cve_prueba_metodo)
JOIN metodos me ON (pm.cve_metodo = me.cve_metodo)
JOIN pruebas p ON (pr.cve_prueba = p.cve_prueba)
JOIN grupos gh ON (p.cve_grupo = gh.cve_grupo)
JOIN grupos gp ON (gh.cve_grupo_padre = gp.cve_grupo)
JOIN pacientes pa ON (vi.cve_paciente = pa.cve_paciente)
JOIN contratos co ON (vi.cve_contrato = co.cve_contrato AND co.contrato_cerrado = 0)
JOIN resultados_campos rc ON (pr.cve_prueba_resultado = rc.cve_prueba_resultado)
JOIN unidades un ON (rc.cve_unidad = un.cve_unidad)
LEFT JOIN valor_referencia_resultado vr ON (rc.cve_resultado_campo = vr.cve_resultado_campo)
JOIN campos_formatos cf ON (rc.cve_campo_formato = cf.cve_campo_formato)
JOIN grupos_campos_formato gcf ON (cf.cve_grupo_campo_formato = gcf.cve_grupo_campo_formato)
JOIN grupos_campos gc ON (gcf.cve_grupo_campo = gc.cve_grupo_campo)
WHERE vi.cve_visita = 696787
AND cf.solo_lectura = 0
ORDER BY p.orden_prueba, pr.cve_prueba_resultado, gcf.orden_grupo, rc.orden_local, vr.orden_valor);
END;
$function$
;
I try to use:
select * from buscarexamen(123123);
On SQL Script return this:
SQL Error [42601]: ERROR: subquery must return only one column Where: PL/pgSQL function buscarexamen(anyelement) line 3 at RETURN
Really I spend a lot of time finding solutions but until now isn't working.
Any help is really apreciated.
Regards.
Your objective sounds like strange. However you should be able to achieve it by creating a composite type your_composite_type :
CREATE TYPE your_composite_type AS
( folio_paciente folio_paciente_data_type
, cve_visita cve_visita_data_type
, nombre_grupo nombre_grupo_data_type
, cve_grupo cve_grupo_data_type
, cve_visita_prueba cve_visita_prueba_data_type
, cve_prueba cve_prueba_data_type
, nombre_prueba nombre_prueba_data_type
, nombre_metodo nombre_metodo_data_type
, visible_grupo visible_grupo_data_type
, [...]
, nombre_unidad nombre_unidad_data_type
, tiene_valores_referencia tiene_valores_referencia_data_type
) ;
Then the function public.buscarexamen() can return an array of data type your_composite_type :
CREATE OR REPLACE FUNCTION public.buscarexamen(visit anyelement)
RETURNS your_composite_type[] -- instead of anyarray
LANGUAGE plpgsql
AS $function$
BEGIN
return array(SELECT row( fn_folio_paciente(...)
, vi.cve_visita, gp.nombre, gp.cve_grupo
, [...]
, vr.valor_referencia_min, vr.valor_referencia_max, un.nombre
, cf.tiene_valores_referencia
) :: your_composite_type
FROM visitas vi
JOIN [...]
WHERE [...]
ORDER BY p.orden_prueba, pr.cve_prueba_resultado, gcf.orden_grupo, rc.orden_local, vr.orden_valor)
) ;
END;
$function$
;
I am converting SQL stored procedure to PostgreSQL stored function. In this stored function inside Update there is From clause.
I want to know how to use From inside Update? Because I am getting error table name "account" specified more than once
CREATE OR REPLACE FUNCTION ETL_Insert_ModifyData( instID numeric)
RETURNS void
LANGUAGE 'sql'
AS $$
--Account
UPDATE account
SET namount = stg_account.namount,
slocation = stg_account.sLocation,
ndept_id = stg_account.ndept_id ,
account.naccount_cpc_mapping_id = stg_account.naccount_cpc_mapping_id
FROM account
INNER JOIN stg_account ON account.naccount_id = stg_account.naccount_id
INNER JOIN department ON stg_account.ndept_id = department.ndept_id
INNER JOIN accountcpcmapping ON stg_account.naccount_cpc_mapping_id = accountcpcmapping.naccount_cpc_mapping_id
WHERE account.ninst_id = instID
AND department.ninst_id = instID
AND accountcpcmapping.ninst_id = instID
--print 'Account completed '
$$
Move the JOIN condition with account table and stg_account to WHERE clause. Also, you need not refer to account in the SET.
Further, prefer shorter aliases (like one or 2 letters) rather than using complete table names.
UPDATE account
SET
namount = stg_account.namount,
slocation = stg_account.sLocation,
ndept_id = stg_account.ndept_id ,
naccount_cpc_mapping_id = stg_account.naccount_cpc_mapping_id
FROM stg_account
INNER JOIN department ON stg_account.ndept_id = department.ndept_id
INNER JOIN accountcpcmapping ON
stg_account.naccount_cpc_mapping_id = accountcpcmapping.naccount_cpc_mapping_id
WHERE account.naccount_id = stg_account.naccount_id
AND account.ninst_id = instID
AND department.ninst_id = instID
AND accountcpcmapping.ninst_id = instID
I have a scenario,a procedure in which there is for loop in which there is a select query which returns different result each time it run. I have to store each and every result in single variable or array or cursor.Please suggest!!.Below provided is the procedure written in a package:
Package Spec:
TYPE t_product_id IS TABLE OF products.productnr%TYPE
INDEX BY PLS_INTEGER;
TYPE t_product_desc IS TABLE OF varchar(100)
INDEX BY PLS_INTEGER;
Type t_product_psnr IS TABLE OF prodsubs.PSNR%TYPE
INDEX BY PLS_INTEGER;
TYPE t_prod_contractperiod IS TABLE OF prodrul.CONTRPEROFPSNR%TYPE
INDEX BY PLS_INTEGER;
Type t_output IS TABLE OF prodrul.ALLOWEDCUSTTYPES%TYPE
INDEX BY PLS_INTEGER;
Package body:
PROCEDURE x_proc_Validprodcusttypeacctyp (
i_prodnr IN t_product_id,
i_invoiceprd IN prodrul.ALLOWEDINVPERIOD%TYPE,
i_psnr IN t_product_psnr,
i_contactprd IN t_prod_contractperiod,
i_result OUT t_output
)
IS
BEGIN
FOR i IN i_prodnr.FIRST .. i_prodnr.LAST
`LOOP
BEGIN
select PRODUCTNR,PRODUCTUSERKEY,ALLOWEDCUSTTYPES,ALLOWEDACCNTTYPES
into i_result (i)`
from prodrul rul join products prods on rul.PRODUCTNROFPSNR = prods.productnr
where prods.productnr = i_prodnr (i) and ALLOWEDINVPERIOD= i_invoiceprd and CONTRPEROFPSNR= i_contactprd (i)
and prods.productnr not in(select productnr from products where SMARTCARDYN = 1)
and rul.PRODUCTNROFPSNR not in (select PSPRODUCTNR from prodsubs join decoders on prodsubs.PSNR = decoders.DECSCPSNR where prodsubs.PSNR= i_psnr (i));
END;
END LOOP;
END x_proc_Validprodcusttypeacctyp;
You can use sys_refcursor as a collection object to return multiple columns instead of using arrays.
E.g.
CREATE OR REPLACE PROCEDURE x_proc_validprodcusttypeacctyp (
i_prodnr IN t_product_id,
i_invoiceprd IN prodrul.allowedinvperiod%TYPE,
i_psnr IN t_product_psnr,
i_contactprd IN t_prod_contractperiod,
i_result OUT t_output,
o_cursor OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN o_cursor FOR
SELECT productnr, productuserkey, allowedcusttypes, allowedaccnttypes
FROM prodrul rul
JOIN
products prods
ON rul.productnrofpsnr = prods.productnr
WHERE prods.productnr = i_prodnr
AND allowedinvperiod = i_invoiceprd
AND contrperofpsnr = i_contactprd
AND prods.productnr NOT IN (SELECT productnr
FROM products
WHERE smartcardyn = 1)
AND rul.productnrofpsnr NOT IN
(SELECT psproductnr
FROM prodsubs
JOIN
decoders
ON prodsubs.psnr =
decoders.decscpsnr
WHERE prodsubs.psnr = i_psnr);
END;
/
Here is my situation. I know there must be a simple answer, but I am just not well versed in TSQL to know how. Below I have the main query of a stored procedure that selects the data I need. I have it working so far except that I need to call a seperate stored procedure called GetRecordMediaById where I feed it the Id from the PhotoId column, and it selects the BLOB data from the appropriate database which then needs to be its own column in the final query or replace the original PhotoId column.
I have no clue how to go about this. I've tried implementing temp tables, but I could never even get it to execute.
Here is my code:
ALTER PROCEDURE [dbo].[GetRollCallData]
#Ids VARCHAR(255),
#LexiconId INT,
#UUID UNIQUEIDENTIFIER,
#ReadOnly INT
AS
DECLARE #TableCode INT
SET #TableCode = 58
EXEC InsertInSelectionCache #Ids, #UUID, #TableCode, 0
WITH DOACTE AS(
SELECT ROW_NUMBER() OVER(PARTITION BY [File].Id ORDER BY CustomRecordsetId DESC) AS RowNumber, [File].*, FileType2Lexicon.Label as FileTypeLabel, [People].DefaultPhone, [People].InvertedName, CustomFieldValue.Value as DateofArrest
FROM FileType2Lexicon, SelectionCache, [People], [File]
INNER JOIN [CustomRecordSet]
ON [CustomRecordset].RecordId = [File].Id
INNER JOIN CustomFieldValue
ON [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
INNER JOIN [CustomField2Lexicon]
ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
WHERE [File].Id = SelectionCache.RecordId
AND SelectionCache.UUID = #UUID
AND SelectionCache.TableCode = #TableCode -- this is the code for File table
AND [File].Id <> 0
AND [File].FileTypeId = FileType2Lexicon.FileTypeId
AND FileType2Lexicon.LexiconId = #LexiconId
AND [File].ClientIdString = [People].ClientIdString
AND CustomFieldValue.Value <> ''
AND CustomField2Lexicon.Label = 'Date of Arrest'),
PHOTOCTE AS(
SELECT [File].Id, CustomFieldValue.Value as PhotoId
FROM FileType2Lexicon, SelectionCache, [People], [File]
INNER JOIN [CustomRecordSet]
ON [CustomRecordset].RecordId = [File].Id
INNER JOIN CustomFieldValue
ON [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
INNER JOIN [CustomField2Lexicon]
ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
WHERE [File].Id = SelectionCache.RecordId
AND SelectionCache.UUID = #UUID
AND SelectionCache.TableCode = #TableCode -- this is the code for File table
AND [File].Id <> 0
AND [File].FileTypeId = FileType2Lexicon.FileTypeId
AND FileType2Lexicon.LexiconId = #LexiconId
AND [File].ClientIdString = [People].ClientIdString
AND CustomFieldValue.Value <> ''
AND CustomField2Lexicon.Label = 'Booking Photo')
SELECT DOACTE.*, PHOTOCTE.PhotoId
FROM DOACTE
INNER JOIN
PHOTOCTE
ON DOACTE.Id = PHOTOCTE.Id
WHERE DOACTE.RowNumber = 1
EDIT:
Solution for me was to create a scalar function that resolves the Id in the BLOB database and returns the BLOB data.
SELECT DOACTE.*, dbo.GetImagebyId(PHOTOCTE.PhotoId) as Photo,
FROM DOACTE
INNER JOIN
PHOTOCTE
ON DOACTE.Id = PhotoCTE.Id
WHERE DOACTE.RowNumber = 1
You can declare a #table_variable and insert the results from "EXEC InsertInSelectionCache #Ids, #UUID, #TableCode, 0" into the table variable.
Then you can join to the #table_variable in the final query.
See here for examples: How to return temporary table from stored procedure
So I have this query:
select ens_use_new_models_bit from cfo_transaction
inner join dbo.cfo_trans_entity_rel on te_tr_transaction_id=tr_transaction_id
inner join cfo_tran_quote on tq_tr_transaction_id = tr_transaction_id
left outer join cfo_engine_sponsor on ens_rs_sponsor_id = te_co_re_entity_id
where te_rv_rel_type_id=713 and tq_tran_quote_id = 3
It returns a bit value, which can also be NULL. I hardcoded 3 for testing but in reality another proc passes this value in, but that's not important here.
Now, in a stored proc, I need to set a variable that's declared in the proc:
SET #vRtn = NULL
as the string - either 'VBEngines' or 'WFModels', or keep it NULL if the bit from above returns NULL.
'VBEngines' if the bit is off, 'WFModels' if the bit is on.
Then after that, I need to perform a T-SQL condition on the value, to see if it's NULL or not. How would I do this? I'm so bad with SQL.
Thanks.
Assuming that you don't need the bit value itself stored in a variable as that was just a means to an end then this should do it.
select #vRtn = case ens_use_new_models_bit
when 0 then 'VBEngines'
when 1 then 'WFModels'
end /*Implicit Else NULL case*/
from cfo_transaction ...
In the case 0 rows are returned no assignment is made so #vRtn keeps its initial value,
declare #newmodelsbit bit, #vRtn varchar(10)
select #newmodelsbit = ens_use_new_models_bit from cfo_transaction
inner join dbo.cfo_trans_entity_rel on te_tr_transaction_id=tr_transaction_id
inner join cfo_tran_quote on tq_tr_transaction_id = tr_transaction_id
left outer join cfo_engine_sponsor on ens_rs_sponsor_id = te_co_re_entity_id
where te_rv_rel_type_id=713 and tq_tran_quote_id = 3
if #newmodelsbit is null
begin
set #vRtn = null
end
else
begin
if #newmodelsbit = 1 --bit is on
begin
set #vRtn = 'WFModels'
end
else -- bit is off
begin
set #vRtn = ' VBEngines'
end
end