How to get the range between two rows - sql

Table1
ID Value
001 100
002 125
003 150
004 175
005 200
006 225
...
Expected Output
If the user enters a value between 100 to 124, then id should display 001
If the user enters a value between 125 to 149, then id should display 002
If the user enters a value between 200 to 224, then id should display 005
If the user enters a value between 225 to 249, then id should display 006
How to make a query for the above condition.
Need query help

It'd be easier to write query to transformed table like ID, ValueFrom, ValueTo.
For this table:
SELECT MAX(ID)
FROM Table1
WHERE Value <= #value
Basically, if 155 is entered, IDs 1 2 and 3 are returned, then MAX ID is taken (3) which is the answer.

Here you go:
First create the test table:
CREATE TABLE #Temp(ID INT, Val INT)
INSERT INTO #Temp VALUES(1, 100);
INSERT INTO #Temp VALUES(2, 125);
INSERT INTO #Temp VALUES(3, 150);
INSERT INTO #Temp VALUES(4, 175);
INSERT INTO #Temp VALUES(5, 200);
INSERT INTO #Temp VALUES(6, 225);
Set up the test value
DECLARE #value INT
SET #value = 125
If ID is sequential (i.e. 1, 2, 3, 4, 5, etc)
SELECT t1.id
FROM #Temp t1, #Temp t2
WHERE t1.ID = t2.ID -1
AND #value BETWEEN t1.Val AND t2.Val -1
If ID is not sequential (i.e. 1, 2, 5, 7, 8, etc)
;WITH cte AS (SELECT ROW_NUMBER() OVER (ORDER BY id) AS rownum, ID, Val FROM #Temp)
SELECT t1.id
FROM cte t1, cte t2
WHERE t1.rownum = t2.rownum -1
AND #value BETWEEN t1.Val AND t2.Val -1

Get the closest match and return first row previously sorting by value:
select top 1 id
from range
where value <= #value
order by value desc
Or, if you need to incorporate this query into another:
select id
from range
where value = (select max(value) from range where value <= #value)

Use CASE in SELECT statement....
Eg:
declare #c int;
set #c=120;
SELECT
CASE
WHEN #c BETWEEN 100 AND 124 THEN '001'
WHEN #c BETWEEN 125 AND 149 THEN '002'
ELSE 'Other'
END

Related

How do I replace strings of a table from another table column

How do I update/replace the value of the first table from the list of my second table in SQL. Sorry im not so good in using replace() of SQL especially replacing from values base from different table
First table.
ID | Value
======================
1 | Fruits[Apple]
2 | Fruits[Apple,Mango]
3 | Apple[Red,Green]
Second table
Search | Replace
=========================
Apple | Orange
Green | Yellow
You will need some kind of recursive replace.
something like a loop
declare #t1 table (ID int, Value varchar(max))
declare #t2 table (Search varchar(max), ReplaceWith varchar(max))
insert #t1 values (1, 'Fruits[Apple]'),(2, 'Fruits[Apple,Mango]'), (3, 'Apple[Red,Green]')
insert #t2 values ('Apple', 'Orange'),('Green', 'Yellow')
--loop nth times for rows that have more than one match
while exists(select top 1 * from #t1 inner join #t2 on charindex(Search, Value ) > 0)
begin
update #t1
set Value = replace(Value, Search, ReplaceWith)
from #t2
inner join #t1 on charindex(Search, Value ) > 0
end
select * from #t1
results
ID Value
----- -----------------------
1 Fruits[Orange]
2 Fruits[Orange,Mango]
3 Orange[Red,Yellow]
Alternatively, you could use recursive CTE
;with CTE(ID, Value, rec_count)
as (
select distinct ID, Value, 1 as rec_count from #t1 inner join #t2 on charindex(Search, Value ) > 0
union all
select ID, Value = replace(Value, Search, ReplaceWith), rec_count +1
from CTE
inner join #t2 on charindex(Search, Value ) > 0
)
update #t1
set Value= replaced.Value
from #t1 t
inner join
( select distinct ID, Value
from CTE c
where rec_count > 1
and rec_count = (select max(rec_count) from CTE where ID = c.ID) ) replaced on replaced.ID = t.ID
Simply use following UPDATE by cross-joined select statement and enjoy it! ;)
UPDATE tFirst
SET Value = REPLACE(tFirst.Value, tSecond.Search, tSecond.Replace)
FROM
[First] tFirst
CROSS JOIN [Second] tSecond

SQL insert if last value is different

Using SQL Server 2005/2008 I would like to insert a new row if the last value (sorted by _timestamp) inserted is not the same value.
For example:
value | timestamp
100 | "yesterday"
101 | "today"
For the next operation:
A value of 101 should not be inserted as this is the latest value
However a value of 102 should be inserted as the latest value is not this
Why you don't use something like that?
DECLARE #table TABLE(val INT, [timestamp] DATETIME)
INSERT INTO #table
SELECT 100, N'20160112'
UNION ALL
SELECT 101, N'20160113'
SELECT * FROM #table
INSERT INTO #table
SELECT 101, N'20160114'
WHERE 101 <> ISNULL((SELECT TOP 1 val FROM #table
ORDER BY timestamp DESC), -1)
SELECT * FROM #table AS T

SQL Server - insert into using multiple values

I have a set of values in a variable table #vartable
id
34
235
34634
3643536
23
234
I then want to do the following insert -
insert into tableA
values ((select max(tableA_id)+1 from tableA), 2147, (select id from #vartable), 1, 0, 0)
So for each id in the #vartable it does an insert using the id on the row.
How do I go about this?
edit to note that I need to update the first value (select max(tableA_id)+1 from tableA) as increasing by 1 each new row it inserts.
insert into tableA (ColName1,ColName2,ColName3,ColName4,ColName5,ColName6)
Select (select max(tableA_id)+1 from tableA), 2147, id , 1, 0, 0
from #vartable
If you need the Max number to be increment, use below query which use ROW_NUMBER
Insert into tableA (ColName1,ColName2,ColName3,ColName4,ColName5,ColName6)
Select (ROW_NUMBER()
OVER (ORDER BY Id)+(select max(tableA_id) from tableA) )as aRow,
2147, id , 1, 0, 0
From #vartable
Here is fiddle link -- > http://sqlfiddle.com/#!3/cb04f/1

SQL Trigger to split string during insert without a common delimiter and store it into another table

Currently I have a system that is dumping data into a table with the format:
Table1
Id#, row#, row_dump
222, 1, “set1 = aaaa set2 =aaaaaa aaaa dd set4=1111”
I want to take the row dump and transpose it into rows and insert it into another table of the format:
Table2
Id#, setting, value
222, ‘set1’,’aaa’
222, ‘set2’,’aaaaaa aaaa dd’
222, ‘set4’,’1111’
Is there a way to make a trigger in MSSQL that will parse this string on insert in Table1 and insert it into Table2 properly?
All of the examples I’ve found required a common delimiter. ‘=’ separates the setting from the value, space(s) separate a value from a setting but a value could have spaces in it (settings do not have spaces in them so the last word before the equal sign is the setting name but there could be spaces between the setting name and equal sign).
There could be 1-5 settings and values in any given row. The values can have spaces. There may or may not be space between the setting name and the ‘=’ sign.
I have no control over the original insert process or format as it is used for other purposes.
You could use 'set' as a delimiter. This is a simple sample. It obviously may have to be molded to your environment.
use tempdb
GO
IF OBJECT_ID('dbo.fn_TVF_Split') IS NOT NULL
DROP FUNCTION dbo.fn_TVF_Split;
GO
CREATE FUNCTION dbo.fn_TVF_Split(#arr AS NVARCHAR(2000), #sep AS NCHAR(3))
RETURNS TABLE
AS
RETURN
WITH
L0 AS (SELECT 1 AS C UNION ALL SELECT 1) --2 rows
,L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B) --4 rows (2x2)
,L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B) --16 rows (4x4)
,L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B) --256 rows (16x16)
,L4 AS (SELECT 1 AS C FROM L3 AS A, L3 AS B) --65536 rows (256x256)
,L5 AS (SELECT 1 AS C FROM L4 AS A, L4 AS B) --4,294,967,296 rows (65536x65536)
,Nums AS (SELECT row_number() OVER (ORDER BY (SELECT 0)) AS N FROM L5)
SELECT
(n - 1) - LEN(REPLACE(LEFT(#arr, n-1), #sep, N'')) + 1 AS pos,
SUBSTRING(#arr, n, CHARINDEX(#sep, #arr + #sep, n) - n) AS element
FROM Nums
WHERE
n <= LEN(#arr) + 3
AND SUBSTRING(#sep + #arr, n, 3) = #sep
AND N<=100000
GO
declare #t table(
Id int,
row int,
row_dump varchar(Max)
);
insert into #t values(222, 1, 'set1 = aaaa set2 =aaaaaa aaaa dd set4=1111')
insert into #t values(111, 2, ' set1 =cx set2 =4444set4=124')
DECLARE #t2 TABLE(
Id int,
Setting VARCHAR(6),
[Value] VARCHAR(50)
)
insert into #t2 (Id,Setting,Value)
select
Id,
[Setting]='set' + left(LTRIM(element),1),
[Value]=RIGHT(element,charindex('=',reverse(element))-1)
from #t t
cross apply dbo.fn_TVF_Split(row_dump,'set')
where pos > 1
order by
id asc,
'set' + left(LTRIM(element),1) asc
select *
from #t2
Update
You could do something like this. It is not optimal and could probably be better handled in the transformation tool or application. Anyway here we go.
Note: You will need the split function I posted before.
declare #t table(
Id int,
row int,
row_dump varchar(Max)
);
insert into #t values(222, 1, 'set1 = aaaa set2 =aaaaaa aaaa dd set3=abc set4=1111 set5=7373')
insert into #t values(111, 2, 'set1 =cx set2 = 4444 set4=124')
DECLARE #t2 TABLE(
Id int,
Setting VARCHAR(6),
[Value] VARCHAR(50)
)
if OBJECT_ID('tempdb.dbo.#Vals') IS NOT NULL
BEGIN
DROP TABLE #Vals;
END
CREATE TABLE #Vals(
Id INT,
Row INT,
Element VARCHAR(MAX),
pos int,
value VARCHAR(MAX)
);
insert into #Vals
select
Id,
row,
element,
pos,
Value=STUFF(LEFT(element,len(element) - CHARINDEX(' ',reverse(element))),1,1,'')
from(
select
Id,
row,
row_dump = REPLACE(REPLACE(REPLACE(row_dump,'= ','='),' =','='),'=','=|')
from #t
) AS t
cross apply dbo.fn_TVF_Split(row_dump,'=')
where pos >=1 and pos < 10
insert into #t2 (Id,Setting,Value)
select
t1.Id,
Setting =
(
SELECT TOP 1
CASE WHEN t2.pos = 1
THEN LTRIM(RTRIM(t2.element))
ELSE LTRIM(RTRIM(RIGHT(t2.element,CHARINDEX(' ',REVERSE(t2.element)))))
END
FROM #Vals t2
where
t2.Id = t1.id
and t2.row = t1.row
and t2.pos < t1.pos
ORDER BY t2.pos DESC
),
t1.Value
from #Vals t1
where t1.pos > 1 and t1.pos < 10
order by t1.id,t1.row,t1.pos
select * from #t2

Display the row by row wise

Using SQL Server 2000
table1
ID Value
101 100
102 200
103 500
I have only 3 row in the table. I want to make in row wise view
Expected Output
101 102 103
100 200 500
How to make a select query for the above condition.
Need Query Help
If you defenitely know which values you have in ID column you can use query like this:
SELECT
MAX(id_101) AS id_101,
MAX(id_102) AS id_102,
MAX(id_103) AS id_103
FROM (
SELECT
1 AS aux,
CASE WHEN ID = 101 THEN val ELSE null END AS id_101,
CASE WHEN ID = 102 THEN val ELSE null END AS id_102,
CASE WHEN ID = 103 THEN val ELSE null END AS id_103
FROM table1
) AS t(aux, id_101, id_102, id_103)
GROUP BY t.aux;
Assuming that 101, 102, 103 is a column names you can rotate table usign PIVOT:
SELECT *
FROM
(
SELECT id, value
FROM #data1
) p
PIVOT (SUM(value) FOR [id] IN ([101], [102], [103])) AS pvt
Prepare data:
DECLARE #data1 TABLE(id int, value INT)
INSERT INTO #data1 VALUES(101, 100)
INSERT INTO #data1 VALUES(102, 200)
INSERT INTO #data1 VALUES(103, 500)