Concat in function - sql-server

I've an issue when I try to create a function from a working concat select
Here the function
CREATE FUNCTION dbo.afEvrGetConsequencesConcat
(#id_evr int,#type_evr int)
RETURNS varchar(max)
AS
BEGIN
declare #result varchar(max)
set #result= ''
IF #type_evr = 0
BEGIN
SELECT #result = #result + (case when (CEV.ID_CON is null) then CEV.NOM_CEV else CON.NOM_CON end) + ' ; '
from T_CONSEQUENCE_EVRP CEV
left join T_CONSEQUENCE CON on CEV.id_con=CON.id_con
WHERE CEV.id_evr = #id_evr
END
IF #type_evr = 1
BEGIN
SELECT DISTINCT #result = #result + isnull(NOM_PHR,'') + ' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN T_PRODUIT_PHRASE_R PROD_PHR on PROD.ID_PROD=PROD_PHR.ID_PROD
INNER JOIN T_PHRASE_R PHR on PROD_PHR.ID_PHR=PHR.ID_PHR
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PHR.flag_consequence = 1
UNION
SELECT DISTINCT #result = #result + isnull(nom_cons_txt,'') +' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN t_consequence_txt PROD_CONS on PROD.ID_PROD=PROD_CONS.ID_PROD
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PROD.transverse_prod = 1
END
RETURN #result
END
GO
And the message error is 'Msg 444, Niveau 16, État 2, Procédure afEvrGetConsequencesConcat, Ligne 23
Select statements included within a function cannot return data to a client.'
The SELECT above works well outside a function. Each time, I got 1 varchar in #result, that match with the SELECT concat. And this similary function works well too :
CREATE FUNCTION dbo.afEvrGetControleConcat
(#id_evr int,#type_evr int,#type_ctrl int)
RETURNS varchar(8000)
AS
BEGIN
declare #result varchar(8000)
set #result= ''
-- 0 tous
-- 1 date + comm
IF #type_ctrl = 0
BEGIN
SELECT #result = #result + ( CONVERT(VARCHAR(10),date_ctr, 103) + ' - ' + CONVERT(VARCHAR(30),isnull(valeur_mesure,'')) + ' - ' + isnull(unite_mesure,'') + ' - ' + com_ctr ) + ' ;'
FROM t_controle_exposition
WHERE id_evr = #id_evr
END
IF #type_ctrl = 1
BEGIN
SELECT #result = #result + ( CONVERT(VARCHAR(10),date_ctr, 103) + ' - ' + com_ctr ) + ' ;'
FROM t_controle_exposition
WHERE id_evr = #id_evr
END
RETURN #result
END
GO
Then what is the problem ? By logic, I want return a varchar, not a table or any funky data. So I don't unterstand this error message.
Thank for your help.
EDIT: Add a temporary table and insert inside the result of UNION and concat next works well :)
CREATE FUNCTION dbo.afEvrGetConsequencesConcat
(#id_evr int,#type_evr int)
RETURNS varchar(max)
AS
BEGIN
declare #result varchar(max)
set #result= ''
declare #t as table (v varchar(max))
IF #type_evr = 0
BEGIN
SELECT #result = #result + (case when (CEV.ID_CON is null) then CEV.NOM_CEV else CON.NOM_CON end) + ' ; '
from T_CONSEQUENCE_EVRP CEV
left join T_CONSEQUENCE CON on CEV.id_con=CON.id_con
WHERE CEV.id_evr = #id_evr
END
IF #type_evr = 1
BEGIN
insert into #t
SELECT DISTINCT isnull(NOM_PHR,'') + ' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN T_PRODUIT_PHRASE_R PROD_PHR on PROD.ID_PROD=PROD_PHR.ID_PROD
INNER JOIN T_PHRASE_R PHR on PROD_PHR.ID_PHR=PHR.ID_PHR
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PHR.flag_consequence = 1
UNION
SELECT DISTINCT isnull(nom_cons_txt,'') +' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN t_consequence_txt PROD_CONS on PROD.ID_PROD=PROD_CONS.ID_PROD
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PROD.transverse_prod = 1
SELECT #result = #result + v FROM #t
END
RETURN #result
END
GO

I think this is to do with the UNION. Try running:
DECLARE #result varchar(max)
SELECT #result = 'test'
UNION
SELECT #result = 'another'
You will get:
Msg 10734, Level 15, State 1, Line 5
Variable assignment is not allowed in a statement containing a top level UNION, INTERSECT or EXCEPT operator.
If you must do the UNION, you're going to have to return a table, otherwise come up with some other way without the UNION. This could explain why the second function works, as it doesn't have a UNION

Related

How to Show the Correct Column Name and Data Type in T-SQL?

I produced DDLs to create tables on Oracle using T-SQL since my source tables are in SQL Server. While I was using only 4 tables for testing, it produced 4 DDLs but it repeated the name of the last column and the data type of the table even though The number of columns is correct.
For example, TABLE_01 has 6 columns and it repeats the last column name and data type for 6 times.
CREATE TABLE TABLE_01(
ISKEY INT
ISKEY INT
ISKEY INT
ISKEY INT
ISKEY INT
ISKEY INT
);
Here is my code. Does anyone find the reason why it repeats them? I couldn't find the cause.
Please help me to solve this problem. I would appreciate your taking time and sharing knowledge for me.
DECLARE #MyList TABLE (Value NVARCHAR(50))
INSERT INTO #MyList VALUES ('TABLE_01')
INSERT INTO #MyList VALUES ('TABLE_02')
INSERT INTO #MyList VALUES ('TABLE_03')
INSERT INTO #MyList VALUES ('TABLE_04')
DECLARE #VALUE VARCHAR(50)
DECLARE #COLNAME VARCHAR(50) = ''
DECLARE #COLTYPE VARCHAR(50) = ''
DECLARE #COLNUM INT = 0
DECLARE #COL_COUNTER INT = 0
DECLARE #COUNTER INT = 0;
DECLARE #MAX INT = (SELECT COUNT(*) FROM #MyList)
-- Loop for Multiple Tables
WHILE #COUNTER < #MAX
BEGIN
SET #VALUE = (SELECT VALUE FROM
(SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) [index] , Value from #MyList) R
ORDER BY R.[index] OFFSET #COUNTER
ROWS FETCH NEXT 1 ROWS ONLY);
SELECT CONCAT('CREATE TABLE ' , REPLACE(UPPER(#VALUE), '_',''), '(')
PRINT 'CREATE TABLE ' + REPLACE(UPPER(#VALUE), '_','') + '('
SET #COLNUM = 0
SET #COL_COUNTER = 0
;WITH numcol AS
(
select schema_name(tab.schema_id) as schema_name,
tab.name as table_name,
col.column_id,
col.name as column_name,
t.name as data_type,
col.max_length,
col.precision
from sys.tables as tab
inner join sys.columns as col
on tab.object_id = col.object_id
left join sys.types as t
on col.user_type_id = t.user_type_id
where schema_name(tab.schema_id) = 'dbo' AND tab.name = #VALUE
)
SELECT #COLNUM = COUNT(*) OVER (PARTITION BY schema_name, table_name) FROM numcol
-- Loop for Multiple Columns
WHILE #COL_COUNTER < #COLNUM
BEGIN
SET #COLNAME = ''
SET #COLTYPE = ''
SELECT #COLNAME = REPLACE(UPPER(COL.name), '_',''), #COLTYPE = CASE WHEN UPPER(col_type.name) = 'MONEY' THEN ' ' +' NUMBER(19,4)'
WHEN UPPER(col_type.name) = 'REAL' THEN ' ' +' FLOAT(23)'
WHEN UPPER(col_type.name) = 'FLOAT' THEN ' ' +' FLOAT(49)'
WHEN UPPER(col_type.name) = 'NVARCHAR' THEN ' ' +' NCHAR'
ELSE ' ' + UPPER(col_type.name)
END
FROM sys.columns COL
INNER JOIN sys.tables TAB
On COL.object_id = TAB.object_id
left join sys.types as col_type
on col.user_type_id = col_type.user_type_id
WHERE OBJECT_NAME(TAB.object_id) = #VALUE
PRINT #COLNAME + #COLTYPE
SET #COL_COUNTER = #COL_COUNTER + 1
END
PRINT ');'
SET #COUNTER = #COUNTER + 1
END
Thank you.
That' a really horrible way to create an SQL script. It's effectively a cursor, and more difficult to write, it's also completely unnecessary.
You can just build the whole thing in one go using STRING_AGG.
I make no comment on the validity of the result for Oracle, as I don't know Oracle well enough.
DECLARE #table sysname = 'YourTable';
DECLARE #schema sysname = 'dbo';
DECLARE #columns nvarchar(max);
SELECT #columns = STRING_AGG(CONCAT(
' '
REPLACE(UPPER(col.name), '_', ''),
' ',
CASE UPPER(col_type.name)
WHEN 'MONEY' THEN ' NUMBER(19,4)'
WHEN 'REAL' THEN ' FLOAT(23)'
WHEN 'FLOAT' THEN ' FLOAT(49)'
WHEN 'NVARCHAR' THEN ' NCHAR'
ELSE UPPER(col_type.name)
END,
), ',
')
FROM sys.columns col
INNER JOIN sys.tables tab ON col.object_id = tab.object_id
JOIN sys.types as col_type ON col.user_type_id = col_type.user_type_id
JOIN sys.schemas sch ON sch.schema_id = tab.schema_id
WHERE tab.name = #table
AND sch.name = #schema;
SELECT
CONCAT(
'CREATE TABLE ',
REPLACE(UPPER(#table), '_',''),
' (
',
#columns,
'
)'
);

Invalid Object Name - #temptable

This stored procedure creates a table in the database when I make the select * into, and because of that, when there is more than one user, an error appears and says SearchTMP table already exists, this happens even if I make a drop of that table. So I decided to make a temporary table, as the following code shows:
INSERT INTO #SQLTbl(Tablename, WHEREClause)
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
(
SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
CROSS JOIN #SearchStringTbl SearchSTR
WHERE STY.name in ('varchar','char','nvarchar','nchar','text')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
AND Sch.name = chktbls.Schemaname
WHERE ST.name <> '#MyTempTable' -- it was SearchTMP
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME);
UPDATE #SQLTbl SET SQLStatement = 'SELECT * INTO #MyTempTable FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)
Since I didn't want to declare or create the table previously, the temptable will be created in the select * into. But when I try to run the procedure by filling the parameters it says:
>Msg 208, Level 16, State 0, Procedure SP_SearchTables_TEST, Line 265, Invalid object name #MyTempTable
The entire stored procedure:
ALTER PROCEDURE [dbo].[SearchTables_TEST] #SearchStr NVARCHAR(60) ,#GenerateSQLOnly Bit = 0 ,#SchemaNames VARCHAR(500) ='%' AS
SET NOCOUNT ON
DECLARE #MatchFound BIT
SELECT #MatchFound = 0
DECLARE #CheckTableNames Table
(
Schemaname sysname
,Tablename sysname
)
DECLARE #SearchStringTbl TABLE
(
SearchString VARCHAR(500)
)
DECLARE #SQLTbl TABLE
(
Tablename SYSNAME
,WHEREClause VARCHAR(MAX)
,SQLStatement VARCHAR(MAX)
,Execstatus BIT
)
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableParamSQL VARCHAR(MAX)
DECLARE #SchemaParamSQL VARCHAR(MAX)
DECLARE #TblSQL VARCHAR(MAX)
DECLARE #tmpTblname sysname
DECLARE #ErrMsg VARCHAR(100)
IF LTRIM(RTRIM(#SchemaNames)) =''
BEGIN
SELECT #SchemaNames = '%'
END
IF CHARINDEX(',',#SchemaNames) > 0
SELECT #SchemaParamSQL = 'SELECT ''' + REPLACE(#SchemaNames,',','''as SchemaName UNION SELECT ''') + ''''
ELSE
SELECT #SchemaParamSQL = 'SELECT ''' + #SchemaNames + ''' as SchemaName '
SELECT #TblSQL = 'SELECT SCh.NAME,T.NAME
FROM SYS.TABLES T
JOIN SYS.SCHEMAS SCh
ON SCh.SCHEMA_ID = T.SCHEMA_ID
INNER JOIN [DynaForms].[dbo].[Enums_Tables] et on
(et.Id = T.NAME COLLATE Latin1_General_CI_AS) '
INSERT INTO #CheckTableNames
(Schemaname,Tablename)
EXEC(#TblSQL)
IF NOT EXISTS(SELECT 1 FROM #CheckTableNames)
BEGIN
SELECT #ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
IF LTRIM(RTRIM(#SearchStr)) =''
BEGIN
SELECT #ErrMsg = 'Please specify the search string in #SearchStr Parameter'
PRINT #ErrMsg
RETURN
END
ELSE
BEGIN
SELECT #SearchStr = REPLACE(#SearchStr,',,,',',#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,',,','#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,'''','''''')
SELECT #SQL = 'SELECT ''' + REPLACE(#SearchStr,',','''as SearchString UNION SELECT ''') + ''''
INSERT INTO #SearchStringTbl
(SearchString)
EXEC(#SQL)
UPDATE #SearchStringTbl
SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',')
END
INSERT INTO #SQLTbl(Tablename,WHEREClause)
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
(
SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
CROSS JOIN #SearchStringTbl SearchSTR
WHERE STY.name in ('varchar','char','nvarchar','nchar','text')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
AND Sch.name = chktbls.Schemaname
WHERE ST.name <> '#MyTempTable' -- it was SearchTMP
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME);
UPDATE #SQLTbl SET SQLStatement = 'SELECT * INTO #MyTempTable FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)
DELETE FROM #SQLTbl
WHERE WHEREClause IS NULL
DECLARE #output TABLE (Id VARCHAR(50), Name VARCHAR(100))
WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN
SELECT TOP 1 #tmpTblname = Tablename , #SQL = SQLStatement
FROM #SQLTbl
WHERE ISNULL(Execstatus ,0) = 0
IF #GenerateSQLOnly = 0
BEGIN
IF OBJECT_ID('#MyTempTable','U') IS NOT NULL -- this line was uncomment
DROP TABLE #MyTempTable -- this line was uncomment
EXEC (#SQL)
IF EXISTS(SELECT 1 FROM #MyTempTable) -- It was like this: SearchTMP
BEGIN
SELECT #MatchFound = 1
INSERT INTO #output (Id, Name)
Select * from [DynaForms].[dbo].[Enums_Tables] where id in (SELECT parsename(#tmpTblname,1) FROM #MyTempTable) -- It was like this: SearchTMP
END
END
ELSE
BEGIN
PRINT REPLICATE('-',100)
PRINT #tmpTblname
PRINT REPLICATE('-',100)
PRINT replace(#SQL,'INTO #MyTempTable','')
END
UPDATE #SQLTbl
SET Execstatus = 1
WHERE Tablename = #tmpTblname
END
SELECT * FROM #output
IF #MatchFound = 0
BEGIN
SELECT #ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
SET NOCOUNT OFF
OK, so a quick test actually answered this, and i can't believe I missed this (/facepalm). you can't use a INTO clause with dynamic SQL and a Temporary table and reference it afterwards; you need to CREATE the table. Consider the following:
DECLARE #SQL varchar(max);
SET #SQL = 'SELECT 1 AS A, 2 AS B INTO #test;';
EXEC (#SQL);
SELECT *
FROM #test;
DROP TABLE #test;
This returns the error:
Msg 208, Level 16, State 0, Line 5
Invalid object name '#test'.
And now, for the correct way:
DECLARE #SQL varchar(max);
CREATE TABLE #test (A int, B int);
SET #SQL = 'INSERT INTO #test SELECT 1 AS A, 2 AS B';
EXEC (#SQL);
SELECT *
FROM #test;
DROP TABLE #test;
This works fine. Thus, you need to CREATE your temporary table, not use an INTO clause.
Instead of
Object_Id('#MyTempTable','U')
You need to use
Object_Id('tempdb..#MyTempTable','U')
To get the object_id of the temporary table to check if it exists or not.
Temp tables are created in TempDB system database

SQL : Server dynamic PIVOT query

I am trying to make the below Pivot SQL query dynamic.
List of the dynamic customer should be retrieved from below query.
Customer List Query
SELECT
Cust_Name
FROM dbo.Customer
INNER JOIN dbo.Service
ON dbo.Customer.Cust_ID = dbo.Service.Cust_ID
WHERE [Next_Service] BETWEEN '2017-09-01' AND '2015-09-10'
Pivot query
Select *
from
(
select Customer.Cust_Name,Agreementlist.ProductQty,Store.Product_Name as Refill
from dbo.Agreement INNER JOIN dbo.Agreementlist ON dbo.Agreement.Agreement_ID = dbo.Agreementlist.Agreement_ID INNER JOIN dbo.Customer
ON dbo.Customer.Cust_ID = dbo.Agreement.Cust_ID INNER JOIN Store on Store.Pro_ID = dbo.Agreementlist.ProID where CatID='2' and Agreement.Status='Approved'
) x
pivot
(
sum(ProductQty)
for Cust_Name in ("list of customers resulted from the first query")
) p
You can add a cursor to loop over your customers and add them to a variable. This here works.
declare #gruppe nvarchar(max)
declare #gruppeSql nvarchar(max)
declare #SQL nvarchar(max)
DECLARE myCustomers CURSOR FOR
SELECT Cust_Name FROM dbo.Customer INNER JOIN dbo.Service
ON dbo.Customer.Cust_ID = dbo.Service.Cust_ID
WHERE [Next_Service] BETWEEN '2017-09-01' AND '2015-09-10'
set #gruppeSql = ''
OPEN myCustomers
FETCH NEXT FROM myCustomers INTO #gruppe
IF (##FETCH_STATUS>=0)
BEGIN
SET #gruppeSql = #gruppeSql +'[' +#gruppe+']'
FETCH NEXT FROM myCustomers INTO #gruppe
END
WHILE (##FETCH_STATUS<>-1)
BEGIN
IF (##FETCH_STATUS<>-2)
SET #gruppeSql = #gruppeSql + ',[' +#gruppe+']'
FETCH NEXT FROM myCustomers INTO #gruppe
END
CLOSE myCustomers
DEALLOCATE myCustomers
SET #gruppeSql = replace(#gruppesql,'''','')
--select #gruppeSql
SET #SQL = '
Select *
from
(
select Customer.Cust_Name,Agreementlist.ProductQty,Store.Product_Name as
Refill
from dbo.Agreement INNER JOIN dbo.Agreementlist ON
dbo.Agreement.Agreement_ID = dbo.Agreementlist.Agreement_ID INNER JOIN
dbo.Customer
ON dbo.Customer.Cust_ID = dbo.Agreement.Cust_ID INNER JOIN Store on
Store.Pro_ID = dbo.Agreementlist.ProID where CatID=''2'' and
Agreement.Status=''Approved''
) x
pivot
(
sum(ProductQty)
for Cust_Name in ('+#gruppesql+')
) p'
print #sql
exec(#sql)
SQL Print
Result:
I have used this SQL script to create dynamic Pivot
CREATE PROCEDURE [dbo].[dynamicPivot]
(#tablename VARCHAR(250),
#pivotColumn VARCHAR(250),
#groupBy VARCHAR(8000),
#aggregateColumns VARCHAR(250),
#aggregation VARCHAR(250),
#execute INT = 0
)
AS
BEGIN
DECLARE #sql VARCHAR(8000), #pivotcols VARCHAR(8000)= '';
DECLARE #result TABLE(result VARCHAR(8000));
SET #sql = '
declare
#pivotcols varchar(8000) = '''';
with cte as (
select distinct '+#pivotColumn+', ''[''+cast('+#pivotColumn+' as varchar(250))+'']'' col
from '+#tablename+')
select #pivotcols = #pivotcols + col + '',''
from cte
order by '+#pivotColumn+';
set #pivotcols = left(#pivotcols, len(#pivotcols)-1);
select #pivotcols result';
INSERT INTO #result
EXEC (#sql);
SELECT #pivotcols = result
FROM #result;
SET #sql = '
SELECT *
FROM (
SELECT
'+#groupBy+CASE #groupBy
WHEN ''
THEN ''
ELSE ', '
END+#pivotColumn+', '+#aggregateColumns+'
FROM '+#tablename+'
) AS s
PIVOT
(
'+#aggregation+'
FOR '+#pivotColumn+' IN ('+#pivotcols+')
)AS p;';
IF #execute = 0
PRINT(#sql);
ELSE
EXEC (#sql);
END;
GO

I need to link table dbo.RMY_LEAD_TIME and get .StockingLevel and .LeadTime_Days for the var Items

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE FUNCTION [dbo].[udf_BuildPartNumber]
(#storeNo varchar(5), #shipDate datetime, #carNo varchar(50))
RETURNS varchar(2000)
AS
BEGIN
DECLARE #items varchar(2000)
SELECT
#items = ISNULL(#items + '^','') + im.ITEM_NUMBER
FROM
dbo.TRANSFERS t
LEFT OUTER JOIN
MatDump.dbo.ITM_MSTR im ON SUBSTRING(t.cic, 1,9) + '0' = im.CIC
INNER JOIN
dbo.TRANSFER_CARS tc ON t.TRANSFER_ID = tc.TRANSFER_ID
WHERE
t.date_shipped = #shipDate
AND t.TO_STORE_ID = #storeNo
AND tc.CAR_NUM = #carNo
ORDER BY
t.SEQ_OR_ID_NUM
RETURN #items END
I think I need a nested select to capture the info on RMY_LEAD_TIME. This function will either grab LeadTime_Days or StockingLevel.
I can duplicate the function for which ever this skips. I wrote this to get the ITEM_NUMBER and now want to modify this to get the corresponding info from the other table. The ITEM_NUMBER matches the Material_Number on the other table.
ALTER FUNCTION [dbo].[Udf_buildleadtime] (#storeNo VARCHAR(5),
#shipDate DATETIME,
#carNo VARCHAR(50))
returns VARCHAR(2000)
AS
BEGIN
DECLARE #ldTm VARCHAR(2000)
DECLARE #partNum VARCHAR(2000)
SELECT #ldTm = Isnull(#ldTm + '^', '') + leadtime_days
FROM dbo.transfers t
LEFT OUTER JOIN matdump.dbo.itm_mstr im
ON Substring(t.cic, 1, 9) + '0' = im.cic
INNER JOIN dbo.transfer_cars tc
ON t.transfer_id = tc.transfer_id
LEFT JOIN dbo.rmy_lead_time rlt
ON rlt.material_number = im.item_number + '-' +
im.condition_code
WHERE t.date_shipped = #shipDate
AND t.to_store_id = #storeNo
AND tc.car_num = #carNo
ORDER BY t.seq_or_id_num
RETURN #ldTm
END
CREATE FUNCTION [dbo].[Udf_buildleadtime] (#storeNo VARCHAR(5),
#shipDate DATETIME,
#carNo VARCHAR(50))
returns VARCHAR(2000)
AS
BEGIN
DECLARE #ldTm VARCHAR(2000)
DECLARE #partNum VARCHAR(2000)
SELECT #ldTm = Isnull(#ldTm + '^', '') + leadtime_days
FROM dbo.transfers t
LEFT OUTER JOIN matdump.dbo.itm_mstr im
ON Substring(t.cic, 1, 9) + '0' = im.cic
INNER JOIN dbo.transfer_cars tc
ON t.transfer_id = tc.transfer_id
LEFT JOIN dbo.rmy_lead_time rlt
ON rlt.material_number = im.item_number + '-' +
im.condition_code
WHERE t.date_shipped = #shipDate
AND t.to_store_id = #storeNo
AND tc.car_num = #carNo
ORDER BY t.seq_or_id_num
RETURN #ldTm
END
SELECT CASE tc.istruck
WHEN 0 THEN tc.car_num
ELSE tc.car_num + ' (Truck)'
END
AS CarNo,
t.to_store_id
AS ToStore,
dbo.Udf_builditemlistbystore(t.to_store_id, t.date_shipped, tc.car_num)
AS
Contents,
(SELECT Isnull(Substring(e.first_name, 1, 1), '')
+ ' '
+ Isnull(Substring(e.middle_name, 1, 1), '')
+ ' ' + e.last_name
FROM prodgang.dbo.stores s
LEFT OUTER JOIN chris.dbo.employee e
ON s.jobcode = e.jobcode
WHERE s.storeno = t.to_store_id
AND s.division <> 25)
AS Consignee,
(SELECT s.location
FROM prodgang.dbo.stores s
WHERE s.storeno = t.to_store_id
AND s.division <> 25)
AS Destination,
dbo.Udf_buildstockinglevel(t.to_store_id, t.date_shipped, tc.car_num)
AS
StockingLevel,
dbo.Udf_buildleadtime(t.to_store_id, t.date_shipped, tc.car_num)
AS LeadTime
FROM dbo.transfers t
LEFT OUTER JOIN dbo.transfer_cars tc
ON t.transfer_id = tc.transfer_id
WHERE t.date_shipped = #shipDate
AND t.qty_shipped <> 0
ORDER BY t.to_store_id,
t.seq_or_id_num
I called these two functions to return the StockingLevel and LeadTime from the RMY_LEAD_TIME Table. Sean Lange, thank you for your constructive crit. While I was trying to refine my questions, I was able to better do the research myself and get the answers. Thank you again.

Is there a way to create multiple triggers in one script?

I am trying to create multiple triggers with only uploading one script into an Oracle DB / APEX workspace, and running it once.
Here is a brief script compared to the one im trying to use:
create or replace trigger "BI_TEC_ROLES"
before insert on "TEC_ROLES"
for each row
begin
if :NEW."ROLE_ID" is null then
select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual;
end if;
end;
create or replace trigger "BI_TEC_STATUSES"
before insert on "TEC_STATUSES"
for each row
begin
if :NEW."STATUS_ID" is null then
select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual;
end if;
end;
create or replace trigger "BI_TEC_SUBS"
before insert on "TEC_SUBS"
for each row
begin
if :NEW."SUB_ID" is null then
select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual;
end if;
end;
I have tried putting GO in between each individual block, but still only creates the first trigger then gives me an error for the second saying:
Error(7,1): PLS-00103: Encountered the symbol "CREATE"
I am hoping that it is possible to do this. Thank you very much for your time and interest =)
Add a forward slash on a new line after each trigger to execute the command in the buffer:
create trigger...
...
end;
/
Put a slash '/' as the first character on a blank line between each trigger statement. This is the SQL*PLUS equivalent of 'go'.
Yes we can execute multiple procedure/trigger/function in single script using the FORWARD SLASH / inside the sql file.
Like below:
create or replace trigger "BI_TEC_ROLES"
before insert on "TEC_ROLES"
for each row
begin
if :NEW."ROLE_ID" is null then
select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual;
end if;
end;
/
create or replace trigger "BI_TEC_STATUSES"
before insert on "TEC_STATUSES"
for each row
begin
if :NEW."STATUS_ID" is null then
select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual;
end if;
end;
/
create or replace trigger "BI_TEC_SUBS"
before insert on "TEC_SUBS"
for each row
begin
if :NEW."SUB_ID" is null then
select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual;
end if;
end;
/
Then oracle will consider it as new statement/block.
Place a forward slash
/
between the two statements on a separate line.
Oracle will then accept it as a new statement
--Parameter:
-- #InclDrop bit
-- Possible values
-- 0 - Script to drop the triggers is not generated.
-- 1 - Script to drip the triggers is generated.
SET ansi_nulls ON
go
SET quoted_identifier ON
go
ALTER PROCEDURE [dbo].[Createscriptofalltriggers]
#InclDrop BIT =1
AS
DECLARE #SQL VARCHAR(8000),
#Text NVARCHAR(4000),
#BlankSpaceAdded INT,
#BasePos INT,
#CurrentPos INT,
#TextLength INT,
#LineId INT,
#MaxID INT,
#AddOnLen INT,
#LFCR INT,
#DefinedLength INT,
#SyscomText NVARCHAR(4000),
#Line NVARCHAR(1000),
#UserName SYSNAME,
#ObjID INT,
#OldTrigID INT
SET nocount ON
SET #DefinedLength = 1000
SET #BlankSpaceAdded = 0
IF #InclDrop <> 0
SET #InclDrop =1
-- This Part Validated the Input parameters
DECLARE #Triggers TABLE
(
username SYSNAME NOT NULL,
trigname SYSNAME NOT NULL,
objid INT NOT NULL
)
DECLARE #TrigText TABLE
(
objid INT NOT NULL,
lineid INT NOT NULL,
linetext NVARCHAR(1000) NULL
)
INSERT INTO #Triggers
(username,
trigname,
objid)
SELECT DISTINCT A.NAME,
B.NAME,
B.id
FROM dbo.sysusers A,
dbo.sysobjects B,
dbo.syscomments C
WHERE A.uid = B.uid
AND B.type = 'Tr'
AND B.id = C.id
AND C.encrypted = 0
IF EXISTS(SELECT C.*
FROM syscomments C,
sysobjects O
WHERE O.id = C.id
AND O.type = 'Tr'
AND C.encrypted = 1)
BEGIN
PRINT '/*'
PRINT 'The following encrypted triggers were found'
PRINT 'The procedure could not write the script for it'
SELECT DISTINCT A.NAME,
B.NAME,
B.id
FROM dbo.sysusers A,
dbo.sysobjects B,
dbo.syscomments C
WHERE A.uid = B.uid
AND B.type = 'Tr'
AND B.id = C.id
AND C.encrypted = 1
PRINT '*/'
END
DECLARE ms_crs_syscom CURSOR local forward_only FOR
SELECT T.objid,
C.text
FROM #Triggers T,
dbo.syscomments C
WHERE T.objid = C.id
ORDER BY T.objid,
C.colid
FOR READ only
SELECT #LFCR = 2
SELECT #LineId = 1
OPEN ms_crs_syscom
SET #OldTrigID = -1
FETCH next FROM ms_crs_syscom INTO #ObjID, #SyscomText
WHILE ##fetch_status = 0
BEGIN
SELECT #BasePos = 1
SELECT #CurrentPos = 1
SELECT #TextLength = Len(#SyscomText)
IF #ObjID <> #OldTrigID
BEGIN
SET #LineID = 1
SET #OldTrigID = #ObjID
END
WHILE #CurrentPos != 0
BEGIN
--Looking for end of line followed by carriage return
SELECT #CurrentPos = Charindex(Char(13) + Char(10), #SyscomText,
#BasePos)
--If carriage return found
IF #CurrentPos != 0
BEGIN
WHILE ( Isnull(Len(#Line), 0) + #BlankSpaceAdded
+ #CurrentPos - #BasePos + #LFCR ) >
#DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - (
Isnull(Len(#Line),
0
) +
#BlankSpaceAdded )
INSERT #TrigText
VALUES ( #ObjID,
#LineId,
Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText, #BasePos,
#AddOnLen),
N''))
SELECT #Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0
END
SELECT #Line = Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText, #BasePos,
#CurrentPos
-#BasePos +
#LFCR),
N'')
SELECT #BasePos = #CurrentPos + 2
INSERT #TrigText
VALUES( #ObjID,
#LineId,
#Line )
SELECT #LineId = #LineId + 1
SELECT #Line = NULL
END
ELSE
--else carriage return not found
BEGIN
IF #BasePos <= #TextLength
BEGIN
/*If new value for #Lines length will be > then the
**defined length
*/
WHILE ( Isnull(Len(#Line), 0) + #BlankSpaceAdded
+ #TextLength - #BasePos + 1 ) >
#DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - (
Isnull(Len(#Line),
0
) +
#BlankSpaceAdded )
INSERT #TrigText
VALUES ( #ObjID,
#LineId,
Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText,
#BasePos,
#AddOnLen),
N''))
SELECT #Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0
END
SELECT #Line = Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText,
#BasePos,
#TextLength
-#BasePos+1
), N'')
IF Len(#Line) < #DefinedLength
AND Charindex(' ', #SyscomText, #TextLength + 1)
> 0
BEGIN
SELECT #Line = #Line + ' ',
#BlankSpaceAdded = 1
END
END
END
END
FETCH next FROM ms_crs_syscom INTO #ObjID, #SyscomText
END
IF #Line IS NOT NULL
INSERT #TrigText
VALUES( #ObjID,
#LineId,
#Line )
CLOSE ms_crs_syscom
PRINT '-- You should run this result under dbo if your triggers belong to multiple users'
PRINT ''
IF #InclDrop = 1
BEGIN
PRINT '-- Dropping the Triggers'
PRINT ''
SELECT 'If exists(Select * from sysObjects where id =Object_ID(''['
+ username + '].[' + trigname
+ ']'') and ObjectProperty(Object_ID(''['
+ username + '].[' + trigname + ']''), ''ISTRIGGER'')=1) Drop Trigger ['
+ username + '].[' + trigname + '] ' + Char(13)
+ Char(10) + 'GO' + Char(13) + Char(10) + Char(13)
+ Char(10)
FROM #Triggers
END
PRINT '----------------------------------------------'
PRINT '-- Creation of Triggers'
PRINT ''
PRINT ''
DECLARE ms_users CURSOR local forward_only FOR
SELECT T.username,
T.objid,
Max(D.lineid)
FROM #Triggers T,
#TrigText D
WHERE T.objid = D.objid
GROUP BY T.username,
T.objid
FOR READ only
OPEN ms_users
FETCH next FROM ms_users INTO #UserName, #ObjID, #MaxID
WHILE ##fetch_status = 0
BEGIN
PRINT 'SetUser N''' + #UserName + '''' + Char(13)
+ Char(10)
SELECT '-- Text of the Trigger'= CASE lineid
WHEN 1 THEN 'GO' + Char(13) + Char(
10)
+
linetext
WHEN #MaxID THEN linetext + 'GO'
ELSE linetext
END
FROM #TrigText
WHERE objid = #ObjID
ORDER BY lineid
PRINT 'Setuser'
FETCH next FROM ms_users INTO #UserName, #ObjID, #MaxID
END
CLOSE ms_users
PRINT 'GO'
PRINT '------End ------'
DEALLOCATE ms_crs_syscom
DEALLOCATE ms_users
SET nocount ON
DECLARE #return_value INT
How to execute it:
EXEC #return_value = [dbo].[Createscriptofalltriggers]
#InclDrop = 1
SELECT 'Return Value' = #return_value
go

Resources