Increment in the value of each row based on iterations in SQL - sql

How can I have an increment on a column in each row based on the values of other column till specific iterations?
For example:
There are 2 columns Iterations and IncrementRatio. The value of Iterations is 5 and IncrementRatio is 5000. The query is supposed to generate 10 records only. Once the iteration number is reached the remaining rows should keep the last value. So based on this scenario I should be able to get something like this.
MyCount
---------
5000
10000
15000
20000
25000
25000
25000
25000
25000
25000

I assumed you always wanted fixed 10 rows result. This is achieve with CROSS JOIN to a derived table with 10 rows. In the solution, i am using Table Value Constructor to generate 10 rows. You can replace it with a tally table if you have one.
-- create the sample table for demonstration of the query
declare #table table
(
Id int identity,
Iterations int,
IncrementRatio int
)
-- insert original sample data plus one extra
insert into #table values (5, 5000), (3, 1000)
-- the query
select *,
MyCount = case when n < Iterations
then n * IncrementRatio
else Iterations * IncrementRatio
end
from #table
cross join
(
values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
) num (n)

I would use a recursive cte:
with cte as (
select iterations, incrementratio, 1 as i, incrementratio as cnt
from t
union all
select iterations, incrementratio, i + 1,
(case when i < iterations then t.incrementratio + cnt
else cnt
end)
from t
where i < 10
)
select *
from cte;

Related

Add extra rows in result set of query with dummy data in sql server

I have this table let's say Students. If there are 2 students in table and result set gives 2 rows than I want to add 5 more rows with dummy data in it no matter what it says i.e 'Dummy Record' or something.
SELECT FirstName, (SELECT COUNT(*) FROM Student) Total
FROM Student
If the output is like this from above query.
FirstName Total
Isaac Frempong 2
Erick Ortiz 2
I want the output to be like this
FirstName Total
Isaac Frempong 2
Erick Ortiz 2
Dummy Data 2
Dummy Data 2
Dummy Data 2
Dummy Data 2
Dummy Data 2
I hope it's achievable, I'm unable to figure how to apply CASE or IF statements here. Maybe somebody could help.
One method is to use a VALUES() statement to construct the rows:
SELECT FirstName, COUNT(*) OVER () as Total
FROM Student
UNION ALL
SELECT 'Dummy', (SELECT COUNT(*) FROM Student)
FROM (VALUES (1), (2), (3), (4), (5)) v(n);
EDIT:
If you always want 7 rows, use arithmetic:
SELECT FirstName, COUNT(*) OVER () as Total
FROM Student
UNION ALL
SELECT 'Dummy', s.total
FROM (VALUES (1), (2), (3), (4), (5), (6), (7)) v(n) CROSS JOIN
(SELECT COUNT(*) as total FROM Student) s
WHERE v.n <= 7 - s.total;
s
Here is a code working on a table varaibale I called #students
Please replace it by your own table
I have filled this table with some Data, and tested the different cases (records number less then 7 or more than 7, and worked as you wish !)
1) First create a variable table called #mytable which will be filled by n records
n will be 7 if the number of records in your students table is equal or less than 7
n will be the number of records in your student table if it is more than 7
2) Then make a right outer join between your student table to which you add the record number using CTE ,row_number() function.
declare #students as table(id int identity(1,1),firstname nvarchar(50))
insert into #students(firstname) values
('Ali ben Hassine'),
('Mohamed el Aabed'),
('Ali ben Hassine'),
('Mohamed el Aabed'),
('Mohamed el Aabed'),
('Tahar Harbi'),
('Hassine Ayari'),
('Ihsen Trabelsi'),
('Marwa Mostari'),
('Mourad Zmerli'),
('Hafedh Gabsi'),
('Miloud Filali');
declare #mytab as table(n int)
declare #n as int
select #n=count(distinct(firstname)) from #students
if #n<7 set #n=7
declare #i as int
set #i=1
while #i <#n+1
begin
insert into #mytab values(#i)
set #i=#i+1
end;
with cte as
(select row_number() over(partition by 1 order by firstname) r#,firstname,count(1) Total from #students group by firstname)
select isnull(cte.firstname,'Dummy') firstanme,isnull(cte.total,2) Total from cte
right outer join #mytab t2 on cte.r#=t2.n
[![enter image description here][1]][1]

Find missing numbers in a sequence in MS SQL

Say i have a table with an integer column Id. I need to find the missing numbers in a sequence with a maximum returned amount.
If the table is empty and i'm asking for 10, it should return the numbers 1-10.
If the table has 1-5 and i'm asking for 10, it should return the numbers 6,7,8,9,10,11,12,13,14,15.
If the table has 1,2,4,6,9 and im asking for 10, it should return the numbers 3,5,7,8,10,11,12,13,14,15
How can i achive this in one single query using MS SQL?
Thanks in advance!
Try this:
If you need to get more numbers, just increase the WHERE Number<=100.
DECLARE #Tab1 TABLE (ID INT)
INSERT INTO #Tab1 VALUES(1)
INSERT INTO #Tab1 VALUES(3)
INSERT INTO #Tab1 VALUES(5)
INSERT INTO #Tab1 VALUES(7)
INSERT INTO #Tab1 VALUES(9)
;WITH CTE AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number + 1 FROM CTE
WHERE Number<=100
)
SELECT TOP 5 *
FROM CTE
WHERE Number NOT IN(SELECT ID FROM #Tab1)
ORDER BY Number
OPTION (maxrecursion 0);
Existing values:
Number
1
3
5
7
9
OutPut:
Number
2
4
6
8
10
Hope this helps you.
This should work
There are also a system table with numbers
declare #T table (i int primary key);
insert into #T values (1), (2), (4), (6), (9);
declare #count int = 10;
declare #size int = (select count(*) from #T);
with cte as
( select 1 as num
union all
select num + 1
from cte
where num + 1 <= (#count + #size)
)
select top (#count) cte.num
from cte
left join #T t
on t.i = cte.num
where t.i is null
order by cte.num
option ( MaxRecursion 0 );

List Lines per Quantity

I'm probably over thinking this. I have a simple table with Name and Ticket Quantity columns. I want to output a row by row list of the names for each quantity purchased. See example below.
Table:
Name Quantity
-----------------------
Bob 1
Joe 2
Sally 1
Output:
Bob
Joe
Joe
Sally
How could I achieve this in TSQL?
SETUP:
DECLARE #table TABLE (
NAME VARCHAR(10),
Quantity INT
)
INSERT INTO #table
SELECT 'Bob', 1 UNION ALL
SELECT 'Joe', 2 UNION ALL
SELECT 'Sally', 1
Recursive CTE
;WITH Members (
NAME,
Quantity
)
AS (
-- Base case
SELECT NAME,
Quantity
FROM #table
UNION ALL
-- Recursive
SELECT NAME,
Members.Quantity - 1
FROM Members
WHERE Members.Quantity > 1
)
SELECT NAME
FROM Members
OPTION (MAXRECURSION 0)
ORDER BY 1
Result:
Bob
Joe
Joe
Sally
Alternatively you could (per #Martin Smith's suggestion):
DECLARE #numbers TABLE (number INT)
INSERT INTO #numbers (number)
VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
Finally:
SELECT NAME
FROM #table t
INNER JOIN #numbers n ON n.number <= t.Quantity
ORDER BY 1
Result:
Bob
Joe
Joe
Sally
And if you really like recursive CTE's (because they smell good), you could build your numbers table with a recursive CTE. You should be using physical tables and not variable tables as you see here - so that you don't have to build them every time.
;WITH Numbers (Value)
AS (
-- Base case
SELECT 32767 Value
UNION ALL
-- Recursive
SELECT Numbers.Value - 1
FROM Numbers
WHERE Numbers.Value > 1
)
INSERT INTO #numbers (number)
SELECT Value
FROM Numbers
OPTION (MAXRECURSION 32767)

Insert multiple rows into SQL Server

I have two tables
Product (product_id, productName)
ProductSerialNumber (ProductSerialNumber_id, product_id, serialNumber, status)
I have serial numbers 12345679000 to 123456790100 (quantity: 90) for product : MILK
Is there way to do this without using multiple inserts ie
$Sn = 12345679000;
while ($Sn <= 123456790100 )
{
INSERT INTO ProductSerialNumber VALUES(...,...,$Sn,...)
$Sn++;
}
You can do this:
WITH Temp
AS
(
SELECT n
FROM(VALUES(0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS Temp(n)
), nums
AS
(
SELECT id = t1.n * 10 + t2.n + 1
FROM temp AS T1
CROSS JOIN temp AS t2
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber -- You can insert into other columns too
FROM nums;
SQL Fiddle Demo.
Note that: This syntax FROM(VALUES(0), (1), ..., (9)) AS Temp(n) is new to SQL Server-2008, for old versions you can use SELECT ... UNION ALL SELECT ... instead.
However, if possible, you can alter this table and make this column SerialNumber an IDENTITY(12345679000, 1) and it will be auto incremental.
Update 1
For SQL Server 2005, try this:
WITH Temp
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
), nums
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY t1.id) AS id
FROM temp t1, temp t2, temp t3, temp t4
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber
FROM nums
WHERE id <= 100;
Updated SQL Fiddle Demo.
Update 2
*How does this query work? *
Firstly, I define a virtual table with only four values:
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
I defined it inside a Common table expression(CTE), to reuse it later.
Then in the following CTE, I used:
FROM temp t1, temp t2, temp t3, temp t4
This will join the table temp four times with it self, therefore it will give you: 44 = 256 rows. Then I used the ranking function ROW_NUMBER() as a work a round to generate a sequence number of number from 1 to 265.
The last thing is the syntax of INSERT INTO ... SELECT ... to select the numbers <= 100 of the numbers that we already generated from the previous step and inserting them to the table.
Hope this makes sense.
here another method to insert multiple rows with procedure
CREATE PROCEDURE autoInsert
#SerialNumberStart bigint,
#SerialNumberEnd bigint,
#status int,
#productID int
AS
while #SerialNumberStart <= #SerialNumberEnd
begin
BEGIN TRAN
INSERT INTO ProductSerialNumber VALUES(#SerialNumberStart)
--print #SerialNumberStart
COMMIT TRAN;
set #SerialNumberStart=#SerialNumberStart+ 1
end

Turn value into singular row

Current
Name Quantity
---------------
Stella 2
Jennifer 2
Greg 3
Requested result
Name Quantity
---------------
Stella 1
Stella 1
Jennifer 1
Jennifer 1
Greg 1
Greg 1
Greg 1
How should I do it?
declare #T table
(
Name varchar(50),
Sales int
)
insert into #T values
('Stella', '2'),
('Jennifer', '2'),
('Greg', '3')
If the maximum value in the quantity column is known to be less than 32,767, you can use Recursion to generate numbers and join the Numbers to achieve your result.
/*******************************************
Max Recursion Count in SQL Server is 32767
Limitation of 32767 Numbers!
******************************************/
;WITH Numbers (Number) AS
(
SELECT 1
UNION ALL
SELECT 1 + Number FROM Numbers WHERE Number < 100
)
SELECT m.Name,
Quantity = 1
FROM MyTable m
JOIN #numbers n ON m.Quantity <= n.Number
OPTION (MAXRECURSION 32767);
Using recursion and borrowing Michael Fredrickson's setup code:
declare #T table (
Name varchar(50),
Sales int
)
insert into #T values ('Stella', '2')
insert into #T values ('Jennifer', '2')
insert into #T values ('Greg', '3')
-- Recursive verion
;with People (Name, Sales) as
(
select Name, Sales
from #T
union all
select Name, Sales - 1
from People
where Sales - 1 > 0
)
select Name, 1 as Quantity
from People
option (maxrecursion 0) -- Recurse without limit
This seems to run faster on my box (5x faster than Michael Fredrickson's according to query plan, but with many more logical reads), not that it matters much.
You'll probably want to have a pre-populated numbers table to do this:
declare #T table (
Name varchar(50),
Sales int
)
declare #numbers table (
Number int
)
insert into #numbers values (1)
insert into #numbers values (2)
insert into #numbers values (3)
insert into #numbers values (4)
-- Etc... up to however many numbers is the max possible value for sales...
insert into #T values ('Stella', '2')
insert into #T values ('Jennifer', '2')
insert into #T values ('Greg', '3')
SELECT
t.Name,
1 AS Sales
FROM
#T t JOIN
#numbers n ON
t.Sales >= n.Number
ORDER BY t.Name
That's how you could do it, but I'm not sure on why you would want to do it.