2016-08-17 76 views
3

我試圖用XML datatype functions來插入Microsoft SQL Server數據庫。如何將NULL插入到SQL Server DATE字段中*來自XML *

其中一個表字段是可空的DATE列。如果節點缺失,則將其插入爲NULL,這很好。但是,如果節點存在,但在運行XPath查詢時爲空<LastDay/>,則它會將空節點的值解釋爲empty string '' instead of NULL。所以在查看錶格結果時,默認情況下會將日期轉換爲1900-01-01。

我想爲空節點也插入NULL而不是默認的空字符串''或1900-01-01。我怎樣才能得到它插入NULL而不是?

CREATE TABLE myxml 
(
    "id" INT, 
    "name" NVARCHAR(100), 
    "company" NVARCHAR(100), 
    "lastday" DATE 
); 

DECLARE @xml XML = 
'<?xml version="1.0" encoding="UTF-8"?> 
<Data xmlns="http://example.com" xmlns:dmd="http://example.com/data-metadata"> 
    <Company dmd:name="Adventure Works Ltd."> 
     <Employee id="1"> 
      <Name>John Doe</Name> 
      <LastDay>2016-08-01</LastDay> 
     </Employee> 
     <Employee id="2"> 
      <Name>Jane Doe</Name> 
     </Employee> 
    </Company> 
    <Company dmd:name="StackUnderflow"> 
     <Employee id="3"> 
      <Name>Jeff Puckett</Name> 
      <LastDay/> 
     </Employee> 
     <Employee id="4"> 
      <Name>Ill Gates</Name> 
     </Employee> 
    </Company> 
</Data>';  

WITH XMLNAMESPACES (DEFAULT 'http://example.com', 'http://example.com/data-metadata' as dmd) 
INSERT INTO myxml (id,name,company,lastday) 
SELECT 
    t.c.value('@id',   'INT'), 
    t.c.value('Name[1]',  'VARCHAR(100)'), 
    t.c.value('../@dmd:name','VARCHAR(100)'), 
    t.c.value('LastDay[1]', 'DATE') 
FROM @xml.nodes('/Data/Company/Employee') t(c) 

這將產生:

id name   company    lastday 
------------------------------------------------ 
1 John Doe  Adventure Works Ltd. 2016-08-01 
2 Jane Doe  Adventure Works Ltd. NULL 
3 Jeff Puckett StackUnderflow  1900-01-01 
4 Ill Gates StackUnderflow  NULL 

我想實現:

id name   company    lastday 
------------------------------------------------ 
1 John Doe  Adventure Works Ltd. 2016-08-01 
2 Jane Doe  Adventure Works Ltd. NULL 
3 Jeff Puckett StackUnderflow  NULL 
4 Ill Gates StackUnderflow  NULL 

回答

5

你必須使用NULLIF功能,避免默認值從XML選擇飛出。

如果兩個指定表達式相等,則返回空值。

你的查詢將被更改如下:

SELECT 
    t.c.value('@id',   'INT'), 
    t.c.value('Name[1]','VARCHAR(100)'), 
    t.c.value('../@dmd:name', 'VARCHAR(100)'), 
    NULLIF(t.c.value('LastDay[1]', 'DATE'),'') 
FROM @xml.nodes('/Data/Company/Employee') t(c) 

欲瞭解更多有關NULLIF,請this MSDN page

+0

,謝謝!將再接受8分鐘:) –

+2

這很容易,因爲你給了一個美妙的MCVE! – techspider

+0

這是一個非常好的答案(+1),你是對的:這麼棒的MCVE真的很有用! – Shnugo

1

除了techspider是很好的答案,我想展現另一種方法:

.nodes()公司CROSS APPLY .nodes()員工允許一個更清潔的XPath導航和避免你被../@dmd.name使用後退導航。在你的情況下,這可能只是爲了獲取信息,但是可以考慮:如果有一家公司沒有任何員工,那麼你可能會跳過整個公司,否則......(由於CROSS APPLY,我的代碼也會跳過,但是你可以使用OUTER APPLY )。

和你實際的問題:使用內部cast as xs:date會做的XQuery中的邏輯,應該是更快...

WITH XMLNAMESPACES (DEFAULT 'http://example.com', 'http://example.com/data-metadata' as dmd) 
INSERT INTO myxml (id,name,company,lastday) 
SELECT 
    e.value('@id',   'INT'), 
    e.value('Name[1]',  'VARCHAR(100)'), 
    c.value('@dmd:name', 'VARCHAR(100)'), 
    e.value('let $x:=LastDay[1] return $x cast as xs:date?','DATE') 
FROM @xml.nodes('/Data/Company') AS A(c) 
CROSS APPLY c.nodes('Employee') AS B(e) 
當然
相關問題