SQL XMLNS failing with sp_executesql sproc - sql

I have the following:
DECLARE #csXml XML
, #changeStatus XML
, #tNum NVARCHAR(25) = '0001aa17'
SELECT #csXml = ChangeSet
FROM [Issues]
WHERE [TrackingNumber] = #tNum
SET #changeStatus =
(
SELECT NEWID() AS [#id]
, 'me#sample.com' AS [#by]
, '1E910737-D78C-E711-9C04-00090FFE0001' AS [#byAccountId]
, '2018-01-18T18:39:03.220Z' AS [#when]
, 'Status' AS [property/#id]
, 'Status' AS [property/#name]
, 'In Review' AS [property/#old]
, 'Closed' AS [property/#new]
, '' AS [collections]
FOR XML PATH('change')
);
-- Add node to XML...
SET #csXml.modify(N'declare default element namespace "http://www.sample.com/ChangeSet/2017/09";
insert sql:variable("#changeStatus") as last into (/changes)[1]');
SET #ParamDef = N'#TrackingNumber NVARCHAR(25)
, #ChangeSet XML';
SET #sql = 'EXEC [SaveIssue] #TrackingNumber, #ChangeSet';
EXEC [sys].[sp_executesql] #sql
, #paramDef
, #TrackingNumber = #tNum
, #ChangeSet = #csXml;
I am getting back an error of:
Msg 6965, Level 16, State 1, Procedure SaveIssue, Line 27 XML
Validation: Invalid content. Expected element(s):
'{http://www.sample.com/ChangeSet/2017/09}change'. Found: element
'change' instead. Location: /:changes[1]/:change[4].
I understand that the sproc I am calling is throwing this error. What I cannot figure out is how to correctly call this sproc to make it stop! :)
The (truncated) definition for the sproc is:
CREATE PROCEDURE [SaveIssue]
( #TrackingNumber NVARCHAR(25)
, #ChangeSet XML(DOCUMENT Reference.sample) = N'<changes xmlns="http://www.sample.com/ChangeSet/2017/09" />'
)
AS
BEGIN
...
END
I have tried tying the XMLNS definition to the XML declaration(s), casting the final #csXml to XML and back to XML(DOCUMENT ...), etc. Nothing I am so far trying is working. I also tried a WITH XMLNAMESPACE... for the #changeStatus SELECT. I am a bit stumped!

Using a CTE solved this for me. First, I had to change the SET to a SELECT. Then added the WITH XMLNAMESPACE... portion. Here is the corrected piece to create the node I want to insert:
;WITH XMLNAMESPACES (DEFAULT 'http://www.sample.com/ChangeSet/2017/09')
SELECT #changeStatus =
(
SELECT NEWID() AS [#id]
, 'me#sample.com' AS [#by]
, '1E910737-D78C-E711-9C04-00090FFE0001' AS [#byAccountId]
, '2018-01-18T18:39:03.220Z' AS [#when]
, 'Status' AS [property/#id]
, 'Status' AS [property/#name]
, 'In Review' AS [property/#old]
, 'Closed' AS [property/#new]
, '' AS [collections]
FOR XML PATH('change')
);

Related

DDL Trigger execution error on schema changes

I created DDL triggers for SQL Server. After doing some DDL operations like create/alter/drop table, i am getting this following error - 'An error was raised during trigger execution. The batch has been aborted and the user transaction, if any, has been rolled back'. Can anyone help me with it.
Here is the trigger creation script -
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [tr_SCHEMA_CHANGES]
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID('dbo.SCHEMA_CHANGES') IS NOT NULL
BEGIN
BEGIN TRY
DECLARE #Eventdata XML;
SET #Eventdata = EVENTDATA();
INSERT dbo.SCHEMA_CHANGES (
[DateTime]
, [ServerName]
, [ServiceName]
, [SPID]
, [SourceHostName]
, [LoginName]
, [UserName]
, [SchemaName]
, [TABLE_NAME]
, [TargetObjectName]
, [EVENT_TYPE]
, [ObjectType]
, [TargetObjectType]
, [EventData]
, [COMMAND_TEXT]
, [ReplicationAuditId]
, [ReplicationOperation]
, [ReplicationDateTime]
, [RowState]
)
VALUES (
GETUTCDATE()
, ##SERVERNAME
, ##SERVICENAME
, #Eventdata.value('(/EVENT_INSTANCE/SPID)[1]', 'int')
, HOST_NAME()
, #Eventdata.value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/UserName)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/SchemaName)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/ObjectType)[1]', 'nvarchar(128)')
, #Eventdata.value('(/EVENT_INSTANCE/TargetObjectType)[1]', 'nvarchar(128)')
, #Eventdata
, #Eventdata.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(MAX)')
, 0
,'Schema Replication'
, GETUTCDATE()
,'queued'
);
END TRY
BEGIN CATCH
SET #Eventdata= NULL;
END CATCH
END
END
GO
ENABLE TRIGGER [tr_SCHEMA_CHANGES] ON DATABASE
GO
Tried with changes script but same error

Sending same parameter twice in exec

I have a simple stored procedure like this:
[dbo].[getStatusList]
#Extended NVARCHAR(255) = 'Project Status',
#Exclude NVARCHAR(255) = '',
#All BIT = 0
AS
SET NOCOUNT ON
IF (#All = 0)
BEGIN
SELECT
[GeneralKey],
[Label]
FROM
[General]
WHERE
[Extended] = #Extended
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF (#All = 1)
BEGIN
SELECT
0 AS [GeneralKey],
'Any' AS [Label],
0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey],
[Label],
[OrderID]
FROM
[General]
WHERE
[Extended] = #Extended
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
END
That I want to do is exec this stored procedure sending twice #Extended parameter like:
exec getStatusList #Extended = 'title1' AND #Extended = 'title2'
It is not possible to do something like this on exec? To only way to solve this is to add another parameter to stored procedure?
Update
As comments below mentioned, I tried this:
CREATE OR ALTER PROCEDURE usp_Get_StatusListByDesignType
-- Add the parameters for the stored procedure here
#Extended NVARCHAR(MAX),
#Exclude NVARCHAR(255) = '',
#All BIT = 0
AS
SET NOCOUNT ON
IF (#All = 0)
BEGIN
DECLARE #Parameter1 VARCHAR(50)
DECLARE #Parameter2 VARCHAR(50)
;WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) rn
FROM
STRING_SPLIT (#Extended,',')
)
SELECT
#Parameter1 = MAX(CASE WHEN rn = 1 THEN VALUE END),
#Parameter2 = MAX(CASE WHEN rn = 2 THEN VALUE END)
FROM
CTE
SELECT
[GeneralKey], [Label]
FROM
[General]
WHERE
[Extended] IN (SELECT #Parameter1, #Parameter2)
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF (#All = 1)
BEGIN
SELECT
0 AS [GeneralKey],
'Any' AS [Label],
0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey],
[Label],
[OrderID]
FROM
[General]
WHERE
[Extended] IN (SELECT #Parameter1, #Parameter2)
AND [Label] <> #Exclude
ORDER BY
[OrderID];
END
RETURN;
But I get this error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
You can let pass your parameter like para1Val1,para1Val2... connected with , comma.
then use STRING_SPLIT function to split it from , comma then get the parameter.
DECLARE #Extended varchar(max)='title1,titl2'
Here is a simple
DECLARE #Extended varchar(max)='title1,titl2'
select *,row_number() over(order by (select NULL)) rn
from STRING_SPLIT (#Extended,',')
Then you can set parameters in SP.
declare parameters variable, then use row_number make your parameter row number.
next step use condition aggregate function set the parameter in select clause.
declare #parameter1 varchar(50)
declare #parameter2 varchar(50)
;with cte as (
select *,row_number() over(order by (select NULL)) rn
from STRING_SPLIT (#Extended,',')
)
select #parameter1 = MAX(case when rn = 1 then value end),
#parameter2 = MAX(case when rn = 2 then value end)
from cte
sqlfiddle
This method :
exec getStatusList #Extended='title1' AND #Extended = 'title2'
it's not going to work at all as a parameter or a variable in general can only hold one value and nothing more. So, you can't do that unless you execute the store procedure twice and specify the parameters on each one of them. Or you may use loops to do it. But i'm not fan of loops and I always suggests to avoid them as much as possible.
The method that I see it fits your situation is a TVP with some modifications on the store procedure itself.
So, you'll pass the values in comma separate values in #Extended and from the store procedure you'll use IN() and NOT IN() instead of = and <> this will extend it to have more values to compare rather than one value.
Then you can use XML to split the values and turn them into rows.
So we will use this :
SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)')))
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
) D
CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)
You can inject it directly into the store procedure with modifying the operators that I mentioned above, and it will work just fine. but for the code reuse, we will use it as TVP.
CREATE FUNCTION SplitToRows
(
#Extended VARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN
(
SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) Extended
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
) D
CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)
)
Now, you can modify the store procedure to the following :
[dbo].[getStatusList]
#Extended NVARCHAR(255) = 'Project Status'
, #Exclude NVARCHAR(255) = ''
, #All BIT = 0
AS
SET NOCOUNT ON
IF(#All = 0)
BEGIN
SELECT
[GeneralKey]
, [Label]
FROM [General]
WHERE
[Extended] IN( SELECT * FROM dbo.SplitToRows(#Extended) )
AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(#Exclude) )
ORDER BY
[OrderID];
END
ELSE
BEGIN
IF(#All = 1)
BEGIN
SELECT
0 AS [GeneralKey]
, 'Any' AS [Label]
, 0 AS [OrderID]
UNION ALL
SELECT
[GeneralKey]
, [Label]
, [OrderID]
FROM [General]
WHERE
[Extended] IN( SELECT * FROM dbo.SplitToRows(#Extended) )
AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(#Exclude) )
ORDER BY
[OrderID];
END
END
Now, you can pass multiple separated values in #Extended and #Exclude at the same time like this :
#Extended = 'title1, title2, title3'
#Exclude = 'title5, title8'
so both parameters will use the same method.

Dyanamic SQL Query not working

I have a table called procedure look up which stores medical procedures
and have multiple company table for which i had to calculate the procedure fees so i had created a dynamic query for it
below is the query
declare #TableProviderName varchar(500)
,#SQLQuery1 nvarchar(max)
,#MaxRecordSize Int
,#Name varchar(250) = null
,#code varchar(50) = null
set #Name = 'sug'
set #TableProviderName = 'PRD_Tata_Details'
set #MaxRecordSize = 50
set #SQLQuery1 = '
;WITH CTE_Procedure AS
(
select top (#MaxRecordSize1)
GPL_ID_PK as ProcedureID
,GPL_ProcedureType as ProcedureType
,GPL_Code as ProcedureCode
,coalesce(Name,GPL_Name,null)as Procedurename
,GPL_CurrencyType_FK as CurrencyType
,ISNULL(GPL_Description,''NIL'') as ProcedureDescription
,ISNULL(GPL_PatientInstruction,''NIL'')as PatientInstructions
,GPL_ProcedureCategory_FK as ProcedureCategory
,GPL_CategorySpecialization_FK as ProcedureSpecialization
,coalesce(PatientPayable,GPL_ProcedureFee,0) as PatientPayable
,0 as InsurancePayable
,0 as InsuranceDiscount
,1 as ProcedureCount
,0 as IndBillingStatus
,Case
when GeneralProcedureID is not null then ''Insurance Supported''
else ''Insurance not Supported''
end as InsuranceStatus
,ROW_NUMBER( ) OVER ( ORDER BY GPL_Name ASC) as RowNumber
from
dbo.PRD_GeneralProcedure_Lookup
left join '
+ #TableProviderName +
'
on
GeneralProcedureID = GPL_ID_PK
where
GPL_ProcedureType = #ProcedureType1
and
(#Name1 is null or GPL_Name like %#Name1%)
and
(#code1 is null or GPL_Code like %#code1%)
)
Select
*
from
CTE_Procedure
'
Execute sp_executesql #SQLQuery1, N'#MaxRecordSize1 int, #ProcedureType1 tinyint,#Name1 varchar(250)
, #code varchar(50)' ,#MaxRecordSize1 = #MaxRecordSize, #ProcedureType1 = 1 , #Name1 = #Name, #code1 = #code
but when executing error occurs saying
"Incorrect syntax near '#Name1'"
can anyone help me with that where condition side issue
I think It may have something to do with your like statement and the way you pass the parameter.
Have a look at this question Parameters & Like statement.
#Name1 = "'%yourvalue%'"

Inserting records in temporary table in sql server?

In SQL Server, I declare one table and trying to insert records, but it is taking so much time to insert. This is my temp table :
declare #totalAprovals Table(
apptype varchar(max)
, Id varchar(max)
, empno varchar(max)
, empname varchar(max)
, AppliedDate varchar(max)
, rstatus varchar(max)
, LeaveType varchar(max)
, fromdate varchar(max)
, todate varchar(max)
, finyear varchar(max)
, noofdays varchar(max)
, perdate varchar(max)
, pertype varchar(max)
, TotMin varchar(max)
, FrmTime varchar(max)
, ToTime varchar(max)
, ConDate varchar(max)
, Amount varchar(max)
, MaterialDesc varchar(max)
, EstValue varchar(max)
, FromYear varchar(max)
, ToYear varchar(max)
, AvailedFrom varchar(max)
, AvailedTo varchar(max)
, Purpose varchar(max)
, FromPlace varchar(max)
, ToPlace varchar(max)
, ICode varchar(max)
, IDesc varchar(max)
, MgrId varchar(max)
)
and my insert statement :
insert into #totalAprovals
SELECT DISTINCT 'LEAVE' AppType
, CRS.applicationId ID
, CRS.EmpId EmpNo
, ISNULL((
SELECT FirstName
FROM Tbl_Emp_M
WHERE EmpId=CRS.EmpId
)
, CRS.EmpId) EmpName
, CONVERT(VARCHAR(10),LA.LeaveDate,103) AppliedDate
, (CASE ISNULL((
SELECT top 1 CurStatus
FROM Tbl_CRS_Leave_AppHis_T
WHERE stepno=CRS.StepNo-1
and applicationId=CRS.applicationId
AND Status=1
order by StepNo desc),'0')
WHEN '0' THEN 'Applied'
WHEN '1' THEN 'Recommended'
WHEN '2' THEN 'Approved'
END) Rstatus
, LT.LeaveName LeaveType
, CONVERT(VARCHAR(10),LA.FromDate,103) FromDate
, CONVERT(VARCHAR(10),LA.ToDate,103) ToDate
, '' FinYear
, '' NoOfDays
, '' PerDate
, '' PerType
, '' TotMin
, '' FrmTime
, '' ToTime
, '' ConDate
, 0 Amount
, '' MaterialDesc
, 0 EstValue
, '' FromYear
, '' ToYear
, ''AvailedFrom
, '' AvailedTo
, '' Purpose
, '' FromPlace
, '' ToPlace
, '' ICode
, '' IDesc
, CRS.MgrId
FROM Tbl_Leave_App_T LA
, Tbl_CRS_Leave_App_T CRS
, Tbl_Leave_Typ_M LT
, Tbl_Emp_ServiceDetails_T EMS
WHERE CRS.applicationId = LA.ApplicationId
AND LA.LeaveTypeId = LT.LeaveTypeId
and crs.EmpId = ems.EmpId
AND CRS.Status = 1
AND LA.Status = 1
AND LT.Status = 1
and ems.Status = 1
AND CRS.CurStatus IN ('0')
AND YEAR(LA.LeaveDate) = YEAR(GETDATE())
AND la.LeaveTypeId not in (9,12)
AND -- LA.ApplicationId LIKE '%LEV%' AND
CRS.EmpId = EMS.EmpId
and ems.LocationCode IN ('101','102','103','104','AHUP')
and crs.MgrId ='xxxxx'
It is taking 2 to 3 minutes to execute this. What could be the reason? Am I writing wrong process to insert records?
You have a performance problem so investigate it as a performance problem. Use a methodology like Waits and Queues. Follow the SQL Server PErformance Flowchart.
When you post here, always add the exact DDL used to create those tables, including all indexes, and capture and link the execution plans.
Most likely is not the INSERT the problem, but the SELECT. DISTINCT is always a code smell indicating a poorly understood join. The WHERE clause is full of non-sargable predicates.
I got the solution, actually i replace the declaring the table like
"declare #totalAprovals Table" to "create table #totalAprovals now it is working superb. Thank you for replying all.

Delete and insert on same procedure

In my SQL stored procedure, I need to delete and insert on same query. My syntax is below. But my syntax fails to store data. Why does it fail? How do I solve this problem? My syntax is
CREATE PROCEDURE spInsertCollectionInspectionHours
#StartDate DATETIME ,
#EndDate DATETIME ,
#ID BIGINT ,
#VesselName VARCHAR(80) ,
#VoyageNo VARCHAR(15) ,
#PortCode VARCHAR(20) ,
#Terminal VARCHAR(70) ,
#InspectionDate DATETIME ,
#InvoiceHours INT ,
#ManifestType INT ,
#Remarks NVARCHAR(200)
AS
BEGIN
BEGIN
DELETE FROM dbo.InspectionHours
WHERE InspectionDate BETWEEN #StartDate AND #EndDate
END
BEGIN
SELECT #ID = ISNULL(MAX(ID), 0) + 1
FROM [InspectionHours]
INSERT INTO [InspectionHours]
( [ID] ,
[VesselName] ,
[VoyageNo] ,
[PortCode] ,
[Terminal] ,
[InspectionDate] ,
[InvoiceHours] ,
[ManifestType] ,
[Remarks]
)
VALUES ( #ID ,
#VesselName ,
#VoyageNo ,
#PortCode ,
#Terminal ,
#InspectionDate ,
#InvoiceHours ,
#ManifestType ,
#Remarks
)
END
END
If have any questions please ask. Thanks in advance.
check your id field identity property is true or not if it's true or yes then no need to give id in insert statement
Your syntax is fine. This should not produce and error.
Your insert statement is also fine. If it is not throwing an error then something else is going on. Are you sure you are passing parameters? Are you sure you are looking in the correct server/db/table and using the correct query to check? Are you positive it's not throwing an error?