【问题标题】:SQL Compare varchar variable with another varchar variableSQL 将 varchar 变量与另一个 varchar 变量进行比较
【发布时间】:2016-06-13 14:19:37
【问题描述】:

我有一个表名行,其中有 BillId (int) 和 LineReference (Varchar(100) 作为两列。每个 billid 都有 LineReference 值。但是,LineReference 中的值可能不正确。所以我必须验证 LineReference来自已根据账单 ID 具有正确参考值的变量。

例子:

Declare @iCountRef varchar(100) = 1,2,3

BillId   LineReference
100      1,2,
100      1,2,40,34
100      1
100      12

从上表中,我需要更新 LineReference 列。

BillId   LineReference
100      1,2
100      1,2
100      1
100      1

我只能通过与变量进行比较来更新:@iCountRef。 LineReference 列应具有@iCountRef 中的值。 @CountRef 中没有的任何值都应该被删除。如果没有匹配的值,则该列应至少更新为数字 1。

【问题讨论】:

  • 在比较来自 1,2,3 或可能 3,2,1 的参考值时,顺序是强制性的吗?
  • 我从没想过序列问题。我需要尽可能接近这个查询。请帮帮我。
  • 上面的@iCountRef 字符总是会硬编码已知字符1,2,3?
  • 不,这个值是动态的。 - 该值是从函数中填充的。在该函数中,我正在为每个 id 运行一个选择查询。价值是动态的。它只能是一个。或 1,2。或,1,2,3,4,5,6,7,8,9,10 或以上。

标签: sql-server sql-server-2008


【解决方案1】:

1) 从中期或长期来看,我想规范化该数据库以避免此类错误:在字符串/VARCHAR 列中存储值列表。例如,我会使用以下多对多表:

CREATE TABLE dbo.BillItem (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    BilldID INT NOT NOT NULL REFERENCES dbo.Bill(BilldID),
    ItemID INT NOT NULL REFERENCES dbo.Item(ItemID),
    UNIQUE (BillID, ItemID) -- Unique constraint created in order to prevent duplicated rows
);

在这种情况下,一张包含两个项目的账单意味着我必须在dbo.BillItem 表中插入两行。

2)返回原始请求:对于一次性任务,我将使用 XML 和 XQuery(此解决方案以 SELECT 语句结束,但转换为 UPDATE 很简单):

DECLARE @iCountRef VARCHAR(100) = '1,2,3'

DECLARE @SourceTable TABLE (
    BillId          INT,
    LineReference   VARCHAR(8000)
)

INSERT @SourceTable (BillId, LineReference)
VALUES
(100, '1,2,'),
(100, '1,2,40,34'),
(100, '1'),
(100, '12')

DECLARE @iCountRefAsXML XML = CONVERT(XML, '<a><b>' + REPLACE(@iCountRef, ',', '</b><b>') + '</b></a>')

SELECT  *, STUFF(z.LineReferenceAsXML.query('
    for $i in (x/y)
        for $j in (a/b)
            where data(($i/text())[1]) eq data(($j/text())[1])
        return concat(",", ($i/text())[1])
').value('.', 'VARCHAR(8000)'), 1, 1, '') AS NewLineReference
FROM (
    SELECT  *, CONVERT(XML, 
        '<x><y>' + REPLACE(LineReference, ',', '</y><y>') + '</y></x>' + 
        '<a><b>' + REPLACE(@iCountRef, ',', '</b><b>') + '</b></a>'
    ) AS LineReferenceAsXML
    FROM    @SourceTable s
) z

结果:

BillId      LineReference  NewLineReference LineReferenceAsXML                                                      
----------- -------------  ---------------- ------------------------------------------------------------------------
100         1,2,           1 ,2             <x><y>1</y><y>2</y><y /></x><a><b>1</b><b>2</b><b>3</b></a>             
100         1,2,40,34      1 ,2             <x><y>1</y><y>2</y><y>40</y><y>34</y></x><a><b>1</b><b>2</b><b>3</b></a>
100         1              1                <x><y>1</y></x><a><b>1</b><b>2</b><b>3</b></a>                          
100         12             (null)           <x><y>12</y></x><a><b>1</b><b>2</b><b>3</b></a>                         

【讨论】:

  • 如果您有任何问题/疑问,请随时提出。
  • 太棒了..!!!我很荣幸你的帮助..!!非常感谢 ..!!!一个小改动..我请求你..我们添加数字:1,如果没有匹配。如果我必须将其更新为 NULL,而不是不匹配.. 这样做很难吗??
  • @goofyui:查看更新的答案。我删除了ISNULL(..., '1') function。现在,如果没有匹配,则返回 NULL。
  • 非常感谢 .. 但是是否有可能只有 billid 和 linereference 列 ..(我将更新 linereference 列)用新数据。当前查询也有 xml 列..我无法删除它。
  • @goofyui: $i 和 $j = (x/y) 和 (a/b) 集合中的项目 = 它们是具有内部文本的 XML 元素 -> {$i|$j}/ text() 返回当前 XML($i 或 $j)元素的内部文本。
【解决方案2】:
--Create temp table and inserting data:
DECLARE @BillsRefs TABLE (
    BillId int, 
    LineReference nvarchar(100)
)

INSERT INTO @BillsRefs VALUES
(100,      '1,2,'),
(100,      '1,2,40,34'),
(100,      '1'),
(100,      '12')

--Declare variables
DECLARE @iCountRef varchar(100) = '1,2,3',
        @xml xml, @iXml xml

--Convert @iCountRef in XML
SELECT @iXml = CAST('<b>' + REPLACE(@iCountRef,',','</b><b>') + '</b>' as xml)

--@iXml:
--<b>1</b>
--<b>2</b>
--<b>3</b>

--Convert table with data in XML
SELECT @xml = (
SELECT CAST('<s id="'+LineReference+'"><a>' + REPLACE(LineReference,',','</a><a>') + '</a></s>' as xml) 
FROM @BillsRefs
FOR XML PATH('')
)
--@xml:
--<s id="1,2,">
--  <a>1</a>
--  <a>2</a>
--  <a />
--</s>
--<s id="1,2,40,34">
--  <a>1</a>
--  <a>2</a>
--  <a>40</a>
--  <a>34</a>
--</s>
--<s id="1">
--  <a>1</a>
--</s>
--<s id="12">
--  <a>12</a>
--</s>

--Compare values from temp table to @iCountRef
--we convert string to xml - to convert them intoi tables
;WITH final AS (
SELECT DISTINCT
        t.v.value('../@id','nvarchar(100)') as LineReferenceOld, -- @id to take 'id="1,2,40,34"' from xml above
        CASE WHEN s.g.value('.','int') IS NULL THEN 1 ELSE s.g.value('.','int') END as LineReference 
        -- '.' is used to take value inside closed tags
FROM @xml.nodes('/s/a') as t(v) --we takes @xml (look above) and play with its nodes 's' (root for each @id) and `a`
LEFT JOIN @iXml.nodes('/b') as s(g) --we takes @iXml it has only 'b' tags
    ON t.v.value('.','int') = s.g.value('.','int') --here we JOIN both xml by `a` and `b`  tags
)

--In final table we get this:

--LineReferenceOld  LineReference
--1,2,              2
--12                    1
--1,2,40,34         1
--1,2,40,34         2
--1                 1
--1,2,              1

--Final SELECT
SELECT c.BillId,
        STUFF((SELECT DISTINCT  ','+CAST(f.LineReference as nvarchar(10))
        FROM final f
        WHERE c.LineReference = f.LineReferenceOld
        FOR XML PATH('')),1,1,'') as LineReference
FROM @BillsRefs c 

输出:

BillId  LineReference
100     1,2
100     1,2
100     1
100     1

如果需要更新源表:

UPDATE c
SET LineReference = STUFF((SELECT DISTINCT  ','+CAST(f.LineReference as nvarchar(10))
        FROM final f
        WHERE c.LineReference = f.LineReferenceOld
        FOR XML PATH('')),1,1,'')
FROM @BillsRefs c  

【讨论】:

  • 非常感谢。我看到 1 更新为不匹配。为了使 null 不匹配,我必须做什么。我需要两种不同的语法..!!
  • 只是发现很难理解您的语法。如果我必须保持 NULL 不匹配,我无法更改您的语法。请帮助我理解..你的语法。谢谢
  • 嗨!我添加了一些解释 - 请检查。我建议你阅读 MSDN 上的 xml 节点
  • 在 BillRef 表中。LineReference 列可能存在 1a、2a 等值。这需要处理。我明白了,定义了 INT 数据类型。我正在努力处理所有情况。谢谢
  • 然后将此示例添加到您的问题中,并添加有关如何处理这种情况的信息。作为快速解决方法,将 'final' cte 中的所有 'int' 替换为 'nvarchar(10)'。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-01
  • 2011-12-21
  • 2018-06-04
  • 1970-01-01
  • 2021-06-09
  • 2014-02-07
相关资源
最近更新 更多