2017-04-03 20 views
0

我试图匹配两个表,其中一个表将多个值存储为一个字符串。SQL在空字段上加入

在下面我需要从#Orders表排序,#NewProduct.NewProductId每个产品分类的例子。

我遇到的问题是我们有时会推出像“黑色衬衫”这样的新产品, ,然后我们会启动适应该产品的“黑色衬衫Vneck”。

我需要改变两者正确地匹配到#Orders表。所以如果订单有黑色和衬衫,但不是Vneck,它被认为是“黑色衬衫”,但如果订单有黑色和衬衫和Vneck,则它被认为是“黑色衬衫”。

下面的代码是一个例子 - 当前逻辑我使用返回重复与左联接。 另外,假设我们可以修改#NewProducts而不是#Orders的格式。

IF    OBJECT_ID('tempdb.dbo.#NewProducts') IS NOT NULL DROP TABLE #NewProducts 
CREATE TABLE #NewProducts 
(
     ProductType VARCHAR(MAX) 
    , Attribute_1 VARCHAR(MAX) 
    , Attribute_2 VARCHAR(MAX) 
    , NewProductId INT 
) 

INSERT  #NewProducts 
VALUES 
    ('shirt', 'black', 'NULL', 1), 
    ('shirt', 'black', 'vneck', 2), 
    ('shirt', 'white', 'NULL', 3) 


IF    OBJECT_ID('tempdb.dbo.#Orders') IS NOT NULL DROP TABLE #Orders 
CREATE TABLE #Orders 
(
     OrderId INT 
    , ProductType VARCHAR(MAX) 
    , Attributes VARCHAR(MAX) 
) 

INSERT #Orders 
VALUES 
    (1, 'shirt', 'black small circleneck'), 
    (2, 'shirt', 'black large circleneck'), 
    (3, 'shirt', 'black small vneck'), 
    (4, 'shirt', 'black small vneck'), 
    (5, 'shirt', 'white large circleneck'), 
    (6, 'shirt', 'white small vneck') 

SELECT  * 
FROM  #Orders o 
     LEFT JOIN #NewProducts np 
      ON o.ProductType = np.ProductType 
      AND CHARINDEX(np.Attribute_1, o.Attributes) > 0 
      AND (
        CHARINDEX(np.Attribute_2, o.Attributes) > 0 
       OR np.Attribute_2 = 'NULL' 
       ) 
+1

这将不会结束。规范化你的数据,否则你会在字符串匹配地狱(甚至不考虑所有的错误和所有的性能问题)。你可以有一个'PRODUCT',一个'PRODUCT_ATTRIBUTES'和一个'ATTRIBUTES'表,然后根据SELECT * FROM orders INNER JOIN products on orders调用一些东西.product = products.id AND EXISTS(SELECT 1 FROM product_attributes INNER连接属性ON product_attributes.product = attributes.id WHERE product_attributes.product = products.id AND attributes.name = “黑”),并存(SELECT 1 ... WHERE attributes.name = “Vneck”)' – user2722968

+0

这将是理想的但我受到工程团队的支配,他们将属性字段存储为单个字符串。 我可以通过打破字符串,然后使用你的方法来制作temp #attributes表。这会起作用吗? – Fubudis

+0

不是你的问题的答案,而只是一个评论。因为你把引号放在'NULL'附近,所以你会在相关位置插入'NULL'这个单词。这不是'NULL'的意思。你可以关闭引号,但是你还需要对查找NULL的代码进行相应的修改。 –

回答

1

你似乎想最长重叠:

SELECT * 
FROM #Orders o OUTER APPLY 
    (SELECT Top (1) np.* 
     FROM #NewProducts np 
     WHERE o.ProductType = np.ProductType AND 
      CHARINDEX(np.Attribute_1, o.Attributes) > 0 
     ORDER BY ((CASE WHEN CHARINDEX(np.Attribute_1, o.Attributes) > 0 THEN 1 ELSE 0 END) + 
       (CASE WHEN CHARINDEX(np.Attribute_2, o.Attributes) > 0 THEN 1 ELSE 0 END) 
       ) DESC 
    ) np; 

我不能说我很高兴与需要做到这一点。看起来Orders应该包含数字参考实际产品的ID。不过,我可以看到有些时候有必要这样做。

+0

这必须是紧密@GordonLinoff,但我得到的错误'ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式无效,除非TOP,抵消或FOR XML也specified.' –

+0

@ SteveLovell。 。 。在那里应该有一个'TOP(1)',因为你只需要一个匹配的行。 –

+0

这工作。这很慢,但它会完成工作。谢谢! – Fubudis

0

我无法通过我自己的反应得到戈登的答复工作,是中途时,他进来了。他服用的最大重叠想法帮助。我已经调整了NewProducts表格,以便即使Orders表格不可用,也能“标准化”这一方面。代码如下或在rextester.com/ERIF13021

create table #NewProduct 
(
NewProductID int primary key, 
ProductType varchar(max), 
ProductName varchar(max) 
) 

create table #Attribute 
(
AttributeID int primary key, 
AttributeName varchar(max) 
) 

create table #ProductAttribute 
(
NewProductID int, 
AttributeID int 
) 

insert into #NewProduct 
values (1, 'shirt', 'black shirt'), 
     (2, 'shirt', 'black vneck shirt'), 
     (3, 'shirt', 'white shirt') 

insert into #Attribute 
values (1, 'black'), 
     (2, 'white'), 
     (3, 'vneck') 

insert into #ProductAttribute 
values (1,1), 
     (2,1), 
     (2,3), 
     (3,2) 


select top 1 with ties 
* 
from 
(
select 
    o.OrderId, 
    p.NewProductID, 
    p.ProductType, 
    p.ProductName, 
    o.Attributes, 
    sum(case when charindex(a.AttributeName,o.Attributes)>0 then 1 else 0 end) as Matches 
from 
    #Orders o 
    JOIN #Attribute a ON 
    charindex(a.AttributeName,o.Attributes)>0 
    JOIN #ProductAttribute pa ON 
    a.AttributeID = pa.AttributeID 
    JOIN #NewProduct p ON 
    pa.NewProductID = p.NewProductID AND 
    o.ProductType = p.ProductType 
group by 
    o.OrderId, 
    p.NewProductID, 
    p.ProductType, 
    p.ProductName, 
    o.Attributes 
) o2 
order by 
row_number() over (partition by o2.OrderID order by o2.Matches desc)