SQL Join传递给LEFT或SUBSTRING函数的无效长度参数

时间:2016-07-01 16:25:09

标签: sql sql-server sql-server-2008

我的数据库表如下所示:

ID  Value
-------------
1   a1¦aa¦a2
1   b1¦aa¦b2
1   b3¦tt¦b3
2   a2¦aa¦z1
2   b2¦tt¦z2
2   b3¦tt¦z3

我正在尝试将每个值拆分为|作为断点起作用:

Select 
    SUBSTRING(MT.Value, 1, CHARINDEX ( '¦' ,MT.Value) - 1) [part1],
    SUBSTRING(MT.Value, CHARINDEX ( '¦' ,MT.Value) + 1, 2) [part2],
    RIGHT(MT.Value,CHARINDEX('¦',REVERSE(MT.Value),0)-1) [part3]
from 
    mytable MT
where 
    MT.id = 1

但是后来我尝试包含一个连接来匹配id2到id1的记录,其中第三部分匹配,SQL Server抛出错误:

  

传递给LEFT或SUBSTRING函数的长度参数无效。

代码:

Select 
    SUBSTRING(MT.Value, 1, CHARINDEX ( '¦' ,MT.Value) - 1) [part1],
    SUBSTRING(MT.Value, CHARINDEX ( '¦' ,MT.Value) + 1, 2) [part2],
    RIGHT(MT.Value, CHARINDEX('¦', REVERSE(MT.Value), 0) - 1) [part3],  
    mt1.value
Join 
    mytable mt1 on mt1.ID = 2
                and RIGHT(mt.Value, CHARINDEX('¦', REVERSE(mt.Value), 0) - 1) = SUBSTRING(mt1.Value, 1, CHARINDEX ( '¦' , mt1.Value) - 1)
where 
    MT.id = 1
from 
    mytable MT

有没有人知道我还能做什么,或者我哪里出错?

2 个答案:

答案 0 :(得分:1)

您正在“值”列中为“|”执行CHARINDEX,然后减去1.这很可能意味着至少有一条记录,其中字符串中不存在“|”。所以你的CHARINDEX将=零(0)然后你减去1是一个负数。您不能在子字符串或左侧函数中使用负数。

一个解决方案就是填写你的陈述:

[Part1] = 
    CASE
        WHEN CHARINDEX ( '¦' ,MT.Value) = 0 THEN MT.Value
        ELSE SUBSTRING(MT.Value, 1, CHARINDEX ( '¦' ,MT.Value)-1)
    END

答案 1 :(得分:0)

因为你有一个工作的select语句,为什么不把它包装在common table expression (CTE)中。现在您可以重用已返回的列。

为了让每个人都能更轻松地分享您的样本数据,我已将其移动到变量中。

    DECLARE @Sample TABLE
    (
        ID      INT,
        [Value] VARCHAR(8)
    )
;


INSERT INTO @Sample
    (
        ID,
        [Value]
    )
VALUES
    (1,'a1¦aa¦a2'),
    (1,'b1¦aa¦b2'),
    (1,'b3¦tt¦b3'),
    (2,'a2¦aa¦z1'),
    (2,'b2¦tt¦z2'),
    (2,'b3¦tt¦z3')
;

我不完全确定我理解这个要求。所以我最好解释一下我做了什么。此查询将返回共享IDPart1 2的所有ID 1。

WITH CTE AS 
    (
        /* Amended OP original query.
         * WHERE clause dropped and 
         * table name replaced with var.
         */
        SELECT
            Id,
            SUBSTRING(MT.Value, 1, CHARINDEX ( '¦' ,MT.Value)-1)    AS [part1],
            SUBSTRING(MT.Value, CHARINDEX ( '¦' ,MT.Value)+1, 2)    AS [part2],
            RIGHT(MT.Value,CHARINDEX('¦',REVERSE(MT.Value),0)-1)    AS [part3]
        FROM
            @Sample MT
    )
SELECT
    *
FROM
    CTE AS cte1
        INNER JOIN CTE AS cte2      ON cte2.part1 = cte1.part1
WHERE
    cte1.ID = 1
    AND cte2.ID = 2
;