2017-03-07 172 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