【问题标题】:How select rows which contains at least one value from other table and is not equal? TSQL如何从其他表中选择至少包含一个值且不相等的行? TSQL
【发布时间】:2017-07-14 23:54:27
【问题描述】:

根据主题,我的查询有问题。出现问题是因为表未规范化。 DB 的架构如下所示:

表 A 列:

ID - A,A,B,B,C,D (not unique)

AR - "N10 N12", "N1 N2 N3", "N1"

A表中的AR是char(100)

AWS 表中的 ARID 是 char(6)

subselect 的结果是一列,其中包含多行字符。它可以插入到临时表中,但我想任何其他变量类型都无法存储它。

这是一个简化的例子,我想选择 AR 至少包含 N1 的所有行。在实际情况下,我在其他表中的 AR 列中有很多值要查找。

我试过了:

包含 - 它可以工作,但 @table 变量不能与此语句一起使用

查询中的内连接和子查询 - 通常它可以工作,但它的问题是,它只返回值相等的行。例如,当我选择 N1 时,它会被返回,但“N1 N2 N3”不是,它应该在结果中。

我的实际查询:

select * 
from A 
where AR in (select ARID 
             From AWS 
             group by ARID 
             having count(*)>2) 
order by EvaluationTime desc

感谢和问候, B.

【问题讨论】:

  • 请标记您的dbms,AR是什么数据类型?文本、JSON、数组?
  • dbms: sql-server, postgres, oracle, sql-server-2005, ...

标签: sql sql-server database tsql ssms


【解决方案1】:

给定两个包含您提供的值的表(告诉我是否还有更多),您首先需要一种方法将 A.AR 中的值拆分为可管理的字符串。我使用这个用户定义函数:

CREATE FUNCTION [dbo].[UDF_StringDelimiter]
/*********************************************************
**  Takes Parameter "LIST" and transforms it for use    **
**  to select individual values or ranges of values.    **
**                                                      **
**  EX: 'This,is,a,test' = 'This' 'Is' 'A' 'Test'       **
*********************************************************/
    (
          @LIST             VARCHAR(8000)
         ,@DELIMITER        VARCHAR(255)
    )

RETURNS @TABLE TABLE 
    ( 
         [RowID] INT IDENTITY
        ,[Value] VARCHAR(255)
    )
WITH SCHEMABINDING  
AS 
BEGIN
    DECLARE 
         @LISTLENGTH AS SMALLINT
        ,@LISTCURSOR AS SMALLINT
        ,@VALUE AS VARCHAR(255)
    ;
    SELECT 
         @LISTLENGTH = LEN(@LIST) - LEN(REPLACE(@LIST,@DELIMITER,'')) + 1
        ,@LISTCURSOR = 1
        ,@VALUE = ''
    ;
    WHILE @LISTCURSOR <= @LISTLENGTH
    BEGIN

        INSERT INTO @TABLE (Value)
        SELECT 
            CASE
                WHEN @LISTCURSOR < @LISTLENGTH
                    THEN SUBSTRING(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST) - 1)
                ELSE SUBSTRING(@LIST,1,LEN(@LIST))
            END
        ;
        SET @LIST = STUFF(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST),'')
        ;       
        SET @LISTCURSOR = @LISTCURSOR + 1
        ;
    END
    ;
    RETURN
    ;
END
;

然后,用那两张表:

DECLARE @TABLE TABLE (ID CHAR(1), AR VARCHAR(55));
INSERT INTO @TABLE VALUES ('A','N1 N3 N4');
INSERT INTO @TABLE VALUES ('B','N2');
INSERT INTO @TABLE VALUES ('C','N1');
INSERT INTO @TABLE VALUES ('D','N5');
INSERT INTO @TABLE VALUES ('E','N2 N1');

DECLARE @TABLE2 TABLE (RowID INT IDENTITY, ARID VARCHAR(55));
INSERT INTO @TABLE2 (ARID) VALUES ('N1');

使用CROSS APPLYLEFT JOIN,我得到了回复:

SELECT A.ID AS [A.ID], A.AR AS [A.AR],B.ARID AS [B.ARID]
FROM @TABLE A
CROSS APPLY dbo.UDF_StringDelimiter(A.AR,' ') X
INNER JOIN @TABLE2 B
    ON B.ARID = X.Value
ORDER BY ID
;

返回:

A.ID     A.AR       B.ARID
-----------------------------------
A       N1 N3 N4     N1
C       N1           N1
E       N2 N1        N1

当然你也可以把它分组,将它作为一个分隔列表返回,等等。给我更多的细节,也许我可以给你一个更好的回应。

【讨论】:

  • 感谢您的回复。实际上我尝试了您的解决方案,它部分有效,我想我改变了一些错误。在最后一列中,ARID 应该分别放在哪里,我通常有 NULL。当 A.AR 中有一个值时,B.ARID 看起来正确,但是当至少有两个值时,B.ARID 为 NULL。
  • 这很令人惊讶,因为我创建的示例数据包括A.AR.(变量@TABLE)中的单值、双值和多个值。如果你只运行SELECT * FROM dbo.UDF_StringDelimiter(A.AR,' '),你会得到什么?
  • A.AR 中是否存在 B.ARID 中不存在的值?
  • 当我将左连接更改为内连接查询返回正确的值,但只有这个在 A 表的 AR 列中有一个值。运行您粘贴的查询,我收到“Msg 4104, Level 16, State 1, Line 60 The multi-part identifier "A.AR could not be bound."。A.AR 中不应该有任何值'在 B.ARID 中不存在,但它可以以相反的方式存在 - 可以在 B.ARID 中存在不存在于 A.AR 中的值。
  • 但是您只想返回 A.AR 中存在的值,对吗?
【解决方案2】:

如果您使用 2 张桌子,CROSS APPLY 是您的朋友。

create  table #ARID(id varchar(10), ar varchar(100));
insert into #ARID values
('a', 'n1 n2'),
('a', 'n10 n11'),
('b', 'n1'),
('b', 'n11 n13 15'),
('c', 'n3'),
('c', 'n14 n12');

这是包含要搜索的值的表:

create table #TO_SEARCH(val varchar(10))
insert into #TO_SEARCH values ('n10'), ('n11');

这个简单的查询返回包含至少一个这些值的每一行:

SELECT ca.*
FROM   #TO_SEARCH ts
CROSS APPLY  (SELECT id, ar
              FROM   #ARID
              WHERE ar LIKE ('%' + ts.val + '%')
             ) ca

你可以反转表格,结果是一样的:

SELECT id, ar
FROM   #ARID
CROSS APPLY  (SELECT val from #TO_SEARCH) ts
WHERE ar LIKE ('%' + ts.val + '%')

+----+------------+
| id | ar         |
+----+------------+
| a  | n10 n11    |
+----+------------+
| a  | n10 n11    |
+----+------------+
| b  | n11 n13 15 |
+----+------------+

可以在这里查看:http://rextester.com/CUEU92118

【讨论】:

    猜你喜欢
    • 2022-01-27
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多