2013-08-23 88 views
2

我有一個表與產品價值如下:反向串

  1. 蘋果iPhone

  2. 蘋果iPhone

  3. 三星手機

  4. 手機三星

我想刪除這是完全相反的(我認爲他們爲重複)表的那些產品,從而代替4條記錄,我的表只需要2個記錄

  1. 蘋果iPhone

  2. 三星手機

我明白,有在SQL Server REVERSE功能,但它會扭轉整個字符串,它不是我要找的。

我非常感謝任何建議/想法。

+1

有沒有永遠只兩個字? –

+0

也可以有兩個以上的單詞。 – pk188

+0

我知道你打電話給iPhone的時候,因爲蘋果只有一個品牌......但是不得不支持Galaxy S/Y/II/III/IV/Grand Duos/Grand Quattro/Win/Note/Note 2/Tab/Tab 2 7.0「,我認爲」三星手機「以相同的名稱呼叫很多不同的東西...... – Renan

回答

5

假設你的字典裏沒有包含任何XML實體(例如><),並且它是不實際手動創建一堆UPDATE語句爲表中單詞的每個組合(如果是實用,那麼簡化你的生活,不要讀這個答案,並使用Justin's answer),你可以創建這樣的功能:

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

(如果XML是一個問題,there are other, more complex alternatives,如CLR)

然後,你可以這樣做:

DECLARE @x TABLE(id INT IDENTITY(1,1), s VARCHAR(64)); 

INSERT @x(s) VALUES 
    ('apple iphone'), 
    ('iphone Apple'), 
    ('iphone samsung hoochie blat'), 
    ('samsung hoochie blat iphone'); 

;WITH cte1 AS 
(
    SELECT id, Item FROM @x AS x 
    CROSS APPLY dbo.SplitSafeStrings(LOWER(x.s), ' ') AS y 
), 
cte2(id,words) AS 
(
    SELECT DISTINCT id, STUFF((SELECT ',' + orig.Item 
    FROM cte1 AS orig 
    WHERE orig.id = cte1.id 
    ORDER BY orig.Item 
    FOR XML PATH(''), TYPE).value('.[1]','nvarchar(max)'),1,1,'') 
    FROM cte1 
), 
cte3 AS 
(
    SELECT id, words, rn = ROW_NUMBER() OVER (PARTITION BY words ORDER BY id) 
    FROM cte2 
) 
SELECT id, words, rn FROM cte3 
-- WHERE rn = 1 -- rows to keep 
-- WHERE rn > 1 -- rows to delete 
; 

所以你可以,三個熱膨脹係數之後,而不是在上述最後SELECT,說:

DELETE t FROM @x AS t 
    INNER JOIN cte3 ON cte3.id = t.id 
    WHERE cte3.rn > 1; 

什麼應該留在@x

SELECT id, s FROM @x; 

結果:

id s 
-- --------------------------- 
1 apple iphone 
3 iphone samsung hoochie blat 
5

在我看來,你是這個複雜的太多,簡單的更新語句將工作:

UPDATE table SET productname = 'apple iphone' WHERE productname = 'iphone apple' 
+0

這假設你知道所有可能的組合,並且寫所有這些命令並不是太乏味(如果有成千上萬的話呢?)也應該是'= 'apple iphone' - 單引號是T-SQL中的雙引號的字符串分隔符es不是。順便說一句,當你的答案剛好是3秒鐘時,你是如何進行加票的? –

+0

@AaronBertrand我向上投票。從開始就有單引號。 – Renan

+0

首先,是的,它假設。其次,你是正確的,固定的。第三,我不知道 –

3

我不知道如何在SQL做到這一點,但在語言,你用接口SQL,你可以這樣做:

你可以標記每行,以便你有一個單詞的數組,使「iphone蘋果」變成{「iphone」,「蘋果」},然後你可以切換順序元素使用一個通用的交換語句,以便它變成{「apple」,「iphone」},然後您可以將其重新變成一個字符串以製作「apple iphone」

雖然我上面描述的過程是不是所有的很難做到,找出哪些是彼此的複製品(知道翻轉哪些)可能是一個困難的問題上的數據實例

2

築底你已經前提是您可以嘗試如下所示:

如果productname的「正確」格式爲<brand> <product_type>,則可以刪除產品名稱爲not like '<brand>%'的所有產品。

以上情況不會有幫助 - 是否有任何產品命名規則?

如上理念不能應用,創建Split功能:

CREATE FUNCTION [dbo].[Split] 
(
    @String NVARCHAR(4000), 
    @Delimiter NCHAR(1) 
) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH Split(stpos,endpos) 
    AS(
     SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos 
     UNION ALL 
     SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1) 
      FROM Split 
      WHERE endpos > 0 
    ) 
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), 
     'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)- stpos) 
FROM Split 
) 

而且在查詢中使用它:

select 
    (SELECT (', ' + Data) 
    FROM Split(t.textVal, ' ') 
    order by [Data] 
    FOR XML PATH('') 
    ) 
from 
    test t 

這將爲您提供與排序的話產品名稱。有了這個,你可以很容易地找到重複。 第二個查詢是粗糙的邊緣,因爲我必須去afk,但你應該設法平滑它:) 祝你好運

+0

這裏沒有產品命名規則,其他一些例子可以是:「online nokia lumia shop」,「shop lumia nokia online」 – pk188

2

這裏是一個解決方案的兩個或兩個以上的單詞用空格分開。基本上這個想法是使用遞歸CTE按空間拆分,然後爲xml將名稱放回到一起排序。然後,您可以通過新的名稱列組,讓您解除複製列表:

with split as (
    select id, 
    convert(varchar(max), left(name, charindex(' ', name + ' ') - 1)) word, 
    stuff(name, 1, charindex(' ', name + ' '), '') name 
    from products 

    union all 

    select id, 
    convert(varchar(max), left(name, charindex(' ', name + ' ') - 1)) word, 
    stuff(name, 1, charindex(' ', name + ' '), '') name 
    from split where name > '' 
), 
hom as (
    select id, 
    (select word + ' ' 
    from split where id=o.id 
    order by word for xml path('')) name 
    from split o 
) 

select name, min(id) id from hom group by name 

SQLFiddle

+0

如果你添加第三個字(OP已經指出),你的SQLfiddle很快就會崩潰, 。 [新SQLfiddle](http://www.sqlfiddle.com/#!6/7dd16/1) –

+0

2個或更多字的解決方案將涉及一個表值函數..只需一秒 – gordy