I would like to ask how to throw an error in SQL Server when the XML is parsed using OpenXML. Here is an example from Microsoft:
Insert Into Employee
SELECT EmployeeId, FirstName, LastName
FROM OPENXML (#hdoc, '/NewDataSet/Employee',1)
WITH (EmployeeId Integer, FirstName varchar(100), LastName varchar(100)) XMLEmployee
Where XMLEmployee.EmployeeId Not IN (Select EmployeeID from Employee)
What if the root node exists but there is no Employee in it?
Thanks
Try this one -
DECLARE #XML XML
SELECT #XML = '<NewDataSet></NewDataSet>'
IF NOT EXISTS(
SELECT 1
WHERE #XML.exist('/NewDataSet/Employee') = 1
) RAISERROR('Employee not exists', 16, 1)
Full answer (maybe wrong answer, because I need to see XML structure) -
DECLARE #XML XML
SELECT #XML = '<NewDataSet></NewDataSet>'
IF NOT EXISTS(
SELECT 1
WHERE #XML.exist('/NewDataSet/Employee') = 1
) RAISERROR('Employee not exists', 16, 1)
INSERT INTO dbo.Employee (EmployeeId, FirstName, LastName)
SELECT
t.c.value('#EmployeeId', 'INT')
, t.c.value('#FirstName', 'VARCHAR(100)')
, t.c.value('#LastName', 'VARCHAR(100)')
FROM #XML.nodes('/NewDataSet/Employee') t(c)
WHERE t.c.value('#EmployeeId', 'INT') NOT IN (
SELECT EmployeeID
FROM dbo.Employee
)
Related
Lets say I have table T with one column A.
What I would like to achieve as result is xml like this :
<not>
<mes>not important what include</mes>
<A>1</A>
<A>2</A>
<A>3</A>
<A>4</A>
...
</not>
Was trying something similar to :
SELECT
'important' AS [mes],
(select A as [A] from T)- of course that part is incorrect but don't know how to handle it
FROM T2
FOR XML PATH ('not');
Please advice.
Updated QUERY
SET #SQL = '
WITH XMLNAMESPACES (''https://something..'' as ns)
SELECT
Q.DocumentType AS [#type],
Q.ReferenceNo AS [#ref],
Q.Id AS [#id],
D.DocId AS [#docId],
N.NotId AS [#notId],
CONVERT(char(10), N.CreationDate, 126) AS [#notdate],
''mes'' AS [mes/#content],
#mes2 AS [mes/content],
[mes] = ''important'' ,
(select A from '+ Cast(#TableName as VARCHAR(60))+' FOR XML PATH (''''), type)
FROM
[DB].[dbo].[tab1] AS Q
LEFT JOIN [DB].[dbo].[tab2] AS D ON Q.ID=D.ID
LEFT JOIN [DB].[dbo].[tab3] AS N ON D.ID=N.DocId
WHERE
Q.ID='+ Cast(#Id as varchar(15))+'
FOR XML PATH (''not'')';
execute (#SQL);
Perhaps this will help
-- Just a DEMONSTRATIVE Table Variable
--------------------------------------------
Declare #YourTable Table ([A] varchar(50))
Insert Into #YourTable Values
(1)
,(2)
,(3)
,(4)
SELECT [mes] = 'important'
,( Select A from #YourTable For XML Path(''),type )
FOR XML PATH ('not');
Results
<not>
<mes>important</mes>
<A>1</A>
<A>2</A>
<A>3</A>
<A>4</A>
</not>
Problem Statement :
when #a has a single word(Ex. 'name1') OR comma separated string (Example 'name1,name2,name3') then the query should return the manager names of employees with name1 and name2 and name3
when #a has an empty string then return the manager names of all the employees in the emp_master table
I have defined a stored procedure where I pass a variable.
This variable can be a comma separated string, a single word or an empty string.
If the string is comma separated then I split that string and get values based on the return table of split statement
else
I get the related value of the non comma separated data using normal subquery
I have tried to achieve this in the following way
Declare #a varchar(50)= ''
select emp.Name from
emp_master emp
where
(LEN(#a)=0 AND emp.Name in
(
SELECT DISTINCT [Name] FROM
[dbo].[Emp_Master] WHERE [EmpId] IN
(
SELECT
DISTINCT [MGR_ID]
FROM [dbo].[Emp_Master]
)
)
)
OR
emp.Name in (Select * from [dbo].[SplitString](#a, ','))
Details for the above sample:
[dbo].[SplitString] - custom written function : returns a table of split values. So
Select * from [dbo].SplitString
will return
SplitTable
----------
name1
name2
name3
and
Select * from [dbo].[SplitString](',','name1')
will return
SplitTable
----------
name1
[dbo].[Emp_Master] contains data for all the employees
[MGR_ID] is the column which has the employeeID of the employee manager
#a is the input variable
The Database is MS SQL 2008
My current solution(the above insane query) solves my purpose but it is very slow, it would be helpful to get an optimized and faster working solution for the problem
Emp_master Table has 400 000 rows, 30 columns
There are 18 000 managers in that table
CREATE NONCLUSTERED INDEX ix ON dbo.Emp_Master ([MGR_ID])
GO
DECLARE #a VARCHAR(50) = ''
DECLARE #t TABLE (val VARCHAR(50) PRIMARY KEY WITH(IGNORE_DUP_KEY=ON))
INSERT INTO #t
SELECT item = t.c.value('.', 'INT')
FROM (
SELECT txml = CAST('<r>' + REPLACE(#a, ',', '</r><r>') + '</r>' AS XML)
) r
CROSS APPLY txml.nodes('/r') t(c)
SELECT /*DISTINCT*/ [Name]
FROM dbo.Emp_Master e1
WHERE (
#a = ''
AND
e1.[EmpId] IN (SELECT DISTINCT MGR_ID FROM dbo.Emp_Master)
)
OR (
#a != ''
AND
e.Name IN (SELECT * FROM #t)
)
OPTION(RECOMPILE)
TRY THIS
CREATE NONCLUSTERED INDEX IX_MGR_ID_Emp_Master ON dbo.Emp_Master ([MGR_ID])
GO
Create Procedure searchname (#a varchar(255))
as
IF (#a = '')
BEGIN
EXEC Searchname1 #a
END
ELSE
BEGIN
EXEC Searchname2 #a
END
GO
Create Procedure Searchname1 (#a varchar(255))
AS
SELECT DISTINCT [Name] FROM
[dbo].[Emp_Master] m1 WHERE
exists
(
SELECT
*
FROM [dbo].[Emp_Master] m2
WHERE
m1.[EmpId]= m2.[MGR_ID]
)
GO
Create Procedure Searchname2 (#a varchar(max))
AS
Select #a = ' SELECT '''+replace( #a,',',''' Union ALL SELECT ''')+' '''
Create table #names (name varchar(255))
insert into #names
EXEC ( #a )
select emp.Name from
emp_master emp
WHERE
emp.Name in( Select name FRom #names)
option (recompile)
IF YOU ARE ALREADY DEALING WITH SQL INJECTION AT APPLICATION LEVEL
THEN
ALTER procedure [dbo].[Searchname2] (#a varchar(max))
AS
select #a = ''''+replace ( #a,',',''',''')+''''
DECLARE #sql NVARCHAR(MAX) = N'
select distinct emp.Name from
emp_master emp
WHERE
emp.Name in( '+#a+')'
EXEC (#sql)
This question already has answers here:
Combine multiple results in a subquery into a single comma-separated value
(10 answers)
Closed 9 years ago.
I am using SQL Server 2008 and I need to implement this :->
I get a result like this :
Table:-sql query ..............
acc_no name
001-000001 John
001-000001 Bob
001-000001 James
001-000002 Sam
001-000002 Bin
001-000002 Dus
So, the condition is that; multiple persons can have same acc_no. So i want following result:
acc_no name
001-000001 John,Bob,James
001-000002 Sam,Bin,Dus
There are other conditions for displaying the results but I got stuck in displaying this format.
How about something like
DECLARE #Table TABLE(
acc_no VARCHAR(50),
name VARCHAR(50)
)
INSERT INTO #Table (acc_no,name) SELECT '001-000001', 'John'
INSERT INTO #Table (acc_no,name) SELECT '001-000001', 'Bob'
INSERT INTO #Table (acc_no,name) SELECT '001-000001', 'James'
INSERT INTO #Table (acc_no,name) SELECT '001-000002', 'Sam'
INSERT INTO #Table (acc_no,name) SELECT '001-000002', 'Bin'
INSERT INTO #Table (acc_no,name) SELECT '001-000002', 'Dus'
--Concat
SELECT t.acc_no,
stuff(
(
select ',' + t1.name
from #Table t1
where t1.acc_no = t.acc_no
order by t1.name
for xml path('')
),1,1,'') Concats
FROM #Table t
GROUP BY t.acc_no
SQL Fiddle DEMO
Try this one -
DECLARE #temp TABLE
(
ID VARCHAR(20)
, Name VARCHAR(50)
)
INSERT INTO #temp (ID, Name)
VALUES
('001-000001', 'John'),
('001-000001', 'Bob'),
('001-000001', 'James'),
('001-000002', 'Sam'),
('001-000002', 'Bin'),
('001-000002', 'Dus')
SELECT t.ID, STUFF((
SELECT ', ' + t2.Name
FROM #temp t2
WHERE t.ID = t2.ID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM (
SELECT DISTINCT ID
FROM #temp
) t
Output -
ID
-------------------- -------------------
001-000001 John, Bob, James
001-000002 Sam, Bin, Dus
select acc_no,stuff((SELECT distinct ', ' + cast(name as varchar(10))
FROM yourtable t2
where t2.acc_no = t1.acc_no
FOR XML PATH('')),1,1,'')
from yourtable t1
group by acc_no
In the below sql code, what does T(C) mean? What is T and what is C?
declare #employeeData xml --this would be your XML input parameter
set #employeeData = '<employeeData>
<employee LastName="Smith" FirstName="Randolph" EmployeeID="1234567"/>
</employeeData>'
declare #xmlTable table (LastName nvarchar(255), FirstName nvarchar(255), EmployeeID int)
insert into #xmlTable (LastName, FirstName, EmployeeID)
select
C.value('#LastName','nvarchar(255)') as LastName,
C.value('#FirstName','nvarchar(255)') as FirstName,
C.value('#EmployeeID','int') as EmployeeID
from
#employeeData.nodes('/employeeData/employee') T(C)
select * from #xmlTable
Check MSDN: http://msdn.microsoft.com/en-us/library/ms188282.aspx
T - Table
C - Column
I am using SSMS 2008 with the following query:
DECLARE #TestData TABLE
(
address_desc NVARCHAR(100) NULL
,people_id UNIQUEIDENTIFIER NULL
);
INSERT #TestData
SELECT a.address_desc, a.people_id
FROM dbo.address_view a
SELECT a.people_id,
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM #TestData b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM #TestData a
GROUP BY a.people_id
This query works, but I want to make this into a view or function so that I can call it from different stored procs. How can I do this? From what I understand, variables cannot be declared in VIEW statements.
Hong, here is my updated query based on your advice which gives me errors:
DECLARE #TestData TABLE
(
address_desc NVARCHAR(100) NULL
,people_id UNIQUEIDENTIFIER NULL
);
INSERT #TestData
SELECT a.address_desc, a.people_id FROM dbo.address_view a
SELECT a.people_id,
(SELECT address_desc, people_id FROM dbo.address_view),
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM #TestData b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM #TestData a
GROUP BY a.people_id
In your last select query replace #TestData with subquery (SELECT address_desc, people_id FROM dbo.address_view), and then get rid of temp table #TestData.
Try this:
Create View YourView As
SELECT a.people_id,
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM (SELECT address_desc, people_id FROM dbo.address_view) b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM (SELECT address_desc, people_id FROM dbo.address_view) a
GROUP BY a.people_id