2017-03-07 169 views
2

我剛剛開始使用SQL中的查詢,所以我還沒有真正體驗過。SQL Server列拆分

我試圖查看這個,但我不明白它的大部分(並不能說,如果它真的適合我的問題),所以我很想解釋你會做什麼解決它和爲什麼!

我正在處理數據庫,如果你問我,有時候會非常低效地處理數據。

數據庫結構如下:

USE [TestDatabase] 
CREATE TABLE [dbo].[fruits](
...(other columns) 
[diffruits1] int, NOT NULL 
[diffruits2] [varchar](100) NULL, 
... 
) 

此一列(diffruits2)會說這樣的事情:

"apples=1000, bananas=2, oranges=1, blueberries=102" 

現在我的目標是使用例如對於IF語句或其他計算,來自蘋果的1000個值(或來自藍莓的102個值) 。我認爲需要從varchar轉換爲int。

像這樣:

IF diffruits1=103 
BEGIN 

IF apples >= 1000 
BEGIN 
example.statement 
END 
IF blueberries =10 
BEGIN 
example.statement2 
END 

END 

類似的東西。我知道我可以將'='和','之間的列分開,但說實話,我只是不知道如何。我想用它來做一個程序。

+0

你的問題不是clear.see參考知道如何提出一個完善的問題鏈接: https://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ – TheGameiswar

+0

您可以先對結構進行標準化,或者是給定結構且不能更改? –

+2

將這樣的數據存儲在數據庫表中是* bug *。拆分不足以解析這些數據。在加載到數據庫之前,您應該解析數據並將其存儲在精心設計的表格中。所有你需要的是一個帶有'FruitName','Count'和ThatParentTableID列的獨立表格 –

回答

2

如果您無法更改表格結構,則可以使用字符串拆分功能來創建可以使用的視圖。

創建和填充示例表(保存我們這一步在你未來的問題):如果您使用的是SQL服務器2016

CREATE TABLE fruits 
(
    diffruits1 int, 
    diffruits2 varchar(100) 
) 

INSERT INTO fruits VALUES (1, 'apples=1000, bananas=2, oranges=1, blueberries=102') 

,您可以使用內置的STRING_SPLIT功能。對於較低版本,您需要先創建函數。
對於這個答案,我chosed使用基於傑夫MODEN的spliter功能,從阿龍貝特朗的文章Split strings the right way – or the next best way採取:

CREATE FUNCTION dbo.SplitStrings 
(
    @List NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255) 
) 
RETURNS TABLE 
WITH SCHEMABINDING AS 
RETURN 
    WITH E1(N)  AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1), 
     E2(N)  AS (SELECT 1 FROM E1 a, E1 b), 
     E4(N)  AS (SELECT 1 FROM E2 a, E2 b), 
     E42(N)  AS (SELECT 1 FROM E4 a, E2 b), 
     cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42), 
     cteStart(N1) AS (SELECT t.N+1 FROM cteTally t 
         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)) 
    SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) 
    FROM cteStart s; 

一旦你擁有了拆分字符串函數,你可以創建這樣的觀點:

CREATE VIEW vw_Splitted AS 

SELECT diffruits1, 
     LTRIM(RTRIM(LEFT(Item, CHARINDEX('=', Item)-1))) As Name, 
     CAST(RIGHT(Item, LEN(Item) - CHARINDEX('=', Item)) As int) As Value 
FROM fruits 
CROSS APPLY dbo.SplitStrings(diffruits2, ',') 

測試視圖:

SELECT * 
FROM vw_Splitted 

結果:

diffruits1 Name Value 
1   apples 1000 
1   bananas 2 
1   oranges 1 
1   blueberries 102 

你可以看到現場演示上rextester

+0

非常感謝!這就是我需要的 –

+0

[很高興幫助: - )](http://meta.stackoverflow.com/questions/291325/how-to-show-appreciation-to-a-user-on-stackoverflow/291327#291327 ) –

0

這是類似於瑣佩萊德的答案,但我想說明你如何可以使用分離功能在程序運行的條件更你自找的。

rextester演示:http://rextester.com/QXM5706

create table t (id int, diffruits2 varchar(8000)); 
insert into t values 
(1, 'apples=1, bananas=2, oranges=3, blueberries=10') 
,(2, 'apples=1000, bananas=2, oranges=1, blueberries=102'); 

     select 
      t.Id 
     , Ordinal = s.ItemNumber 
     , Fruit = ltrim(left(s.Item,charindex('=',s.Item)-1)) 
     , Quantity = stuff(s.Item,1,charindex('=',s.Item),'') 
     from t 
     cross apply dbo.delimitedsplit8K(diffruits2,', ') s 
go 

回報:

+----+---------+-------------+----------+ 
| Id | Ordinal | Fruit | Quantity | 
+----+---------+-------------+----------+ 
| 1 |  1 | apples  |  1 | 
| 1 |  2 | bananas  |  2 | 
| 1 |  3 | oranges  |  3 | 
| 1 |  4 | blueberries |  10 | 
| 2 |  1 | apples  |  1000 | 
| 2 |  2 | bananas  |  2 | 
| 2 |  3 | oranges  |  1 | 
| 2 |  4 | blueberries |  102 | 
+----+---------+-------------+----------+ 

分割字符串參考:


而你也可以用它在你的程序像這樣:

go 
create procedure dbo.fruitful (@id int) as 
begin; 
    set nocount, xact_abort on; 
    select 
     t.Id 
    , Ordinal = s.ItemNumber 
    , Fruit = ltrim(left(s.Item,charindex('=',s.Item)-1)) 
    , Quantity = stuff(s.Item,1,charindex('=',s.Item),'') 
    into #temp_fruit 
    from t 
    cross apply dbo.delimitedsplit8K(diffruits2,', ') s 
    where t.id = @id; 

    if exists (
    select 1 
    from #temp_fruit 
    where Fruit='apples' 
     and Quantity>=1000 
    ) 
    begin; 
    /* steal an apple, or other code */ 
    select 1 as AppleStolen; 
    end; 

    if exists (
    select 1 
    from #temp_fruit 
    where Fruit='blueberries' 
     and Quantity=10 
    ) 
    begin; 
    /* give them 2 more blueberries, just to be nice. or other code. */ 
    select 2 as BlueberriesAdded; 
    end; 
end; 
go 

與ID爲1的添加字符串的例子程序:

exec dbo.fruitful 1; 

r eturns:

+------------------+ 
| BlueberriesAdded | 
+------------------+ 
|    2 | 
+------------------+ 

併爲您的原始字符串:

exec dbo.fruitful 2; 

回報:

+-------------+ 
| AppleStolen | 
+-------------+ 
|   1 | 
+-------------+ 
+0

非常感謝你! –

+0

@JoeyR樂於幫忙! – SqlZim