另一种写这个sql的方法

时间:2012-08-30 03:58:28

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

环境:Sql Server 2008

包含一行包含逗号分隔值的列。

即使该csv中存在单个产品,该行也能得到什么。

这是我可以做到的,但只是想知道是否有另一种方式来写它?

SELECT * FROM REWARDS
WHERE ProductCsv like '%banana%' 
   or ProductCsv like '%strawberry%' 
   or ProductCsv like '%orange%'

4 个答案:

答案 0 :(得分:3)

您当前的查询似乎无法准确捕获您想要的结果。如果我们有这样的行怎么办:

bananaberry cream pie,strawberry shortcake,orange juice

这是否与您的查询匹配?我认为这会更准确:

WHERE ',' + ProductCsv + ',' LIKE '%,banana,%'
   OR ',' + ProductCsv + ',' LIKE '%,strawberry,%'
   OR ',' + ProductCsv + ',' LIKE '%,orange,%'

如果您只是想找到一个项目,这可能会更有效:

WHERE ',' + ProductCsv + ',' LIKE '%,banana,%'

您可能想要使用拆分功能。例如:

CREATE FUNCTION dbo.SplitStrings_XML
(
   @List   NVARCHAR(MAX),
   @Delim  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN 
   (  
      SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
      FROM 
      ( 
        SELECT x = CONVERT(XML, '<i>' + REPLACE(@List, @Delim, '</i><i>') 
        + '</i>').query('.')
      ) AS a CROSS APPLY x.nodes('i') AS y(i)
   );
GO

现在你可以说:

SELECT * FROM dbo.REWARDS AS r
WHERE EXISTS 
(
  SELECT 1 FROM dbo.REWARDS AS r2
  CROSS APPLY dbo.SplitStrings_XML(r2.ProductCsv, ',') AS x
  WHERE x.Item IN ('orange','strawberry','banana')
  AND r2.[key] = r.[key]
);

或更简单:

SELECT DISTINCT r.ProductCsv --, other columns
  FROM dbo.REWARDS AS r
  CROSS APPLY dbo.SplitStrings_XML(r.ProductCsv, ',') AS x
  WHERE x.Item IN ('orange','strawberry','banana');

XML方法有点脆弱,具体取决于可以存储在表中的字符串种类,但有很多选择(包括通过TVP而不是列表或单独的值传递您的集合)。有关拆分函数的更深层次背景,请参阅以下博文:

http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-follow-up

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

所有人都说,我不知道这是否比现在更好。

答案 1 :(得分:1)

使用XML

查看以下示例
DECLARE @Table TABLE(
        CommaList VARCHAR(MAX)
)

INSERT INTO @Table SELECT 'banana,test,hello'
INSERT INTO @Table SELECT 'homer,banana,test,hello'
INSERT INTO @Table SELECT 'homer,banana'
INSERT INTO @Table SELECT '1,2,3'

;WITH XMLValues AS (
        SELECT  *,
                CAST('<d>' + REPLACE(CommaList, ',', '</d><d>') + '</d>' AS XML) XMLValue
        FROM    @Table t
)
, SplitValues AS (
        SELECT  xv.*,
                T2.Loc.value('.','VARCHAR(MAX)') SplitValue
        FROM    XMLValues xv
        CROSS APPLY XMLValue.nodes('/d') as T2(Loc) 
)
SELECT  DISTINCT
        CommaList
FROM    SplitValues
WHERE   SplitValue = 'banana'

xml Data Type Methods

nodes() Method (xml Data Type)

value() Method (xml Data Type)

Using Common Table Expressions

答案 2 :(得分:1)

您可以在表格中存储要比较的所有值

DECLARE @Product_list TABLE(
        products VARCHAR(50)
)

Insert into @Product_list values
('banana'),
('strawberry'),
('orange')

SELECT * FROM REWARDS
join @Product_list
on ProductCsv like '%'+products+'%' 

答案 3 :(得分:0)

您可以使用拆分功能(网上有很多)将ProductsCsv拆分为单个元素,然后将其与香蕉,草莓等进行比较。

理想情况下,您不会将CSV数据存储在列中,而是为其分配一个单独的表。