Reputation: 23
I just started working with Queries in SQL so I'm not really experienced yet.
I tried to look this up, but I didn't understand most of it (and couldn't tell, if it really fits my problem), so I would love to have an explanation of what you would do to solve it and why!
I'm working with a database that sometimes handles data very inefficiently if you ask me.
Database structure is as follows:
USE [TestDatabase]
CREATE TABLE [dbo].[fruits](
...(other columns)
[diffruits1] int, NOT NULL
[diffruits2] [varchar](100) NULL,
...
)
This one column (diffruits2) would say something like that:
"apples=1000, bananas=2, oranges=1, blueberries=102"
Now my goal is to use e.g. that 1000 value from apples (or 102 from blueberries) for an IF statement or other calculations. I thought converting from varchar to int is needed.
Like this:
IF diffruits1=103
BEGIN
IF apples >= 1000
BEGIN
example.statement
END
IF blueberries =10
BEGIN
example.statement2
END
END
Something like that. I knew I could possibly split the column between '=' and ',' but honestly, I just don't know how. I want to use it for a procedure.
Upvotes: 2
Views: 176
Reputation: 38023
This is similar to the answer by Zohar Peled, but I wanted to illustrate more on how you could use the splitting function in the procedure to run the conditions you wanted.
rextester demo: 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
returns:
+----+---------+-------------+----------+
| 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 |
+----+---------+-------------+----------+
Splitting strings reference:
string_split()
in SQL Server 2016 : Follow-Up #1 - Aaron BertrandAnd you would be able to use it in your procedures like so:
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
The example procedure for the added string with id 1:
exec dbo.fruitful 1;
returns:
+------------------+
| BlueberriesAdded |
+------------------+
| 2 |
+------------------+
And for your original string:
exec dbo.fruitful 2;
returns:
+-------------+
| AppleStolen |
+-------------+
| 1 |
+-------------+
Upvotes: 0
Reputation: 82474
If you can't change the table structure, you can use a string splitting function to create a view that you can work with.
Create and populate sample table (Please save us this step in your future questions):
CREATE TABLE fruits
(
diffruits1 int,
diffruits2 varchar(100)
)
INSERT INTO fruits VALUES (1, 'apples=1000, bananas=2, oranges=1, blueberries=102')
If you are using sql-server 2016, you can use the built-in STRING_SPLIT
function. For lower versions you need to create the function first.
For this answer I've chosed to use a function based on Jeff Moden's spliter, taken from Aaron Bertrand's article 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;
Once you have the split string function, you can create the view like this:
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, ',')
Test the view:
SELECT *
FROM vw_Splitted
Results:
diffruits1 Name Value
1 apples 1000
1 bananas 2
1 oranges 1
1 blueberries 102
You can see a live demo on rextester:
Upvotes: 2