missing number or max number from the list - sql

I am looking for missing number in the list, it works perfectly fine but when it start from 2, would it be possible to get 1. in below insertion
it should provide 1 not 4. please help thanks
drop table #temp
create table #temp
(
Number INT
)
insert into #temp
(Number)
select 2 union all
select 3 union all
select 5
SELECT MIN(t1.Number) + 1 AS MissingNumber
FROM #temp t1
LEFT OUTER JOIN #temp t2 ON (t1.Number + 1 = t2.Number)
WHERE t2.Number IS NULL

I will suggest you to create a separate numbers table to do this.
There a many ways to create number table. Check this link for more info
SELECT TOP (1000) n = Row_number()OVER (ORDER BY number)
INTO #numbers
FROM [master]..spt_values
ORDER BY n;
CREATE TABLE #temp
(Number INT)
INSERT INTO #temp(Number)
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 5
SELECT Min(t1.n) AS MissingNumber
FROM #numbers t1
LEFT OUTER JOIN #temp t2
ON ( t1.n = t2.Number )
WHERE t2.Number IS NULL

I think its not possible because join doesn't knows that number starts from 1. it will search for min value.
we can use while loop to solve problem

use this
IF OBJECT_ID('Tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp ( Number INT )
INSERT INTO #temp
( Number )
VALUES ( 2 ),
( 3 ),
( 5 );
WITH cte
AS ( SELECT n = 1
UNION ALL
SELECT n + 1
FROM cte
WHERE n <= 100 --can be increased with OPTION ( MAXRECURSION {iteration value} ) at the end of the query
)
SELECT MIN(cte.n) AS MissingNumber
FROM cte
LEFT JOIN #temp t ON ( cte.n = t.Number )
WHERE t.Number IS NULL

Related

Creating sequence in SQL with different length

I have a table with the customer identifier as PK and his time to maturity in months:
Customer | Maturity
---------+-----------
1 80
2 60
3 52
4 105
I want to create a table which will have customer identifier and the maturity will be defined as sequence of number with the increment + 1:
Customer | Maturity
---------+------------
1 1
1 2
1 ....
1 80
2 1
2 2
2 ...
2 60
I don't know whether I should use a sequence or the cross join or how to solve this problem.
one way is to use recursive CTE.
; with cte as
(
select Customer, M = 1, Maturity
from yourtable
union all
select Customer, M = M + 1, Maturity
from yourtable
where M < Maturity
)
select *
from cte
option (MAXRECURSION 0)
You can try joining your current table to a sequence table to generate the maturity ranges you want.
WITH cte AS (
SELECT 1 AS seq
UNION ALL
SELECT seq + 1
FROM cte
WHERE seq < 500
)
SELECT
t1.Customer,
t2.seq AS Maturity
FROM yourTable t1
INNER JOIN cte t2
ON t2.seq <= t1.Maturity
ORDER BY
t1.Customer,
t2.seq
OPTION (MAXRECURSION 0);
Demo here:
Rextester
you can try query like below
create table t (Customer int, Maturity int)
insert into t values
(1,80)
,(2,60)
,(3,52)
,(4,105);
select Customer, r from
t cross join
(select top (select max(maturity) from t)
row_number() over( order by (select NULL)) r
from sys.objects s1 cross join sys.objects s2) k
where r<=Maturity
order by Customer asc,r asc
see live demo
You can try the below.
Created two temporary tables to represent your tables in below example.
You need to replace them with you table names and drop the first three lines.
declare #Customer table (Customer int, Maturity int)
declare #NewTable table (Customer int, Maturity int)
insert #Customer select 1, 80
declare #x int = 0
declare #iterations table (x int)
while #x <= (select max(Maturity) from #Customer)
begin
set #x += 1
insert #iterations select #x
end
insert #NewTable
select c.Customer, i.x from #Customer c left join #iterations i on i.x <= c.Maturity
select * from #NewTable
Late answer, but another option is an ad-hoc tally table in concert with a CROSS APPLY
Example
Select A.customer
,Maturity = B.N
From YourTable A
Cross Apply (
Select Top (A.Maturity) N=Row_Number() Over (Order By (Select NULL))
From master..spt_values n1
) B

Can I delete multiple of nth rows in a single query from a table in SQL?

I want to delete multiple of 4 from my table which have thousands of record. How can I do it?
Ex:-
Table1
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
I want to delete every 4th row.
I don't want to use a loop or cursor.
Delete A from
(
Select *,Row_Number() Over(Order By Id) as RN from TableA
) A
where RN%4=0
SQL Fiddle Link
Try this...
delete from table_name where (col1 % 4) = 0
Use a CTE.
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY t.rowfield) AS rank
FROM Table1 t)
SELECT rowfield, fielda
FROM cte
WHERE rank%4 != 0
Output
rowfield fielda
1 a
2 b
3 c
5 e
6 f
7 g
9 i
SQL Fiddle: http://sqlfiddle.com/#!6/c9540b/13/0
Once you are happy with the output use DELETE FROM.
This can use an index if one exists and uses numbers table
;with cte
as
(select n from numbers
where n%4=0
)
delete t
from table1 t
join
cte c
on c.n=t.id
Try this
DECLARE #nvalToDelete varchar(100)='4,7,3,8,9'-- just give values to delete from table
DECLARE #temp TABLE
(
valtodelete VARCHAR(100)
)
DECLARE #Deletetemp TABLE
(
valtodelete INT
)
INSERT INTO #temp
SELECT #nvalToDelete
INSERT INTO #Deletetemp
SELECT split.a.value('.', 'VARCHAR(1000)') AS valToDelete
FROM (SELECT Cast('<S>' + Replace(valtodelete, ',', '</S><S>')
+ '</S>' AS XML) AS valToDelete
FROM #temp) AS A
CROSS apply valtodelete.nodes('/S') AS Split(a)
DECLARE #Table1 TABLE
(
ID INT,
val varchar(10)
)
INSERT INTO #Table1
SELECT 1,'a' UNION ALL
SELECT 2,'b' UNION ALL
SELECT 3,'c' UNION ALL
SELECT 4,'d' UNION ALL
SELECT 5,'e' UNION ALL
SELECT 6,'f' UNION ALL
SELECT 7,'g' UNION ALL
SELECT 8,'h' UNION ALL
SELECT 9,'i'
SELECT *
FROM #Table1;
WITH cte
AS (SELECT *,
RN = Row_number()
OVER (
ORDER BY id )
FROM #Table1)
DELETE FROM #Table1
WHERE id IN(SELECT id FROM cte
WHERE rn IN (SELECT CASt(valToDelete AS INT) FROM #Deletetemp)
)
SELECT *
FROM #Table1

Split a row on 2 or more rows depending on a column

I have a question
If I have one row that looks like this
|ordernumber|qty|articlenumber|
| 123125213| 3 |fffff111 |
How can I split this into three rows like this:
|ordernumber|qty|articlenumber|
| 123125213| 1 |fffff111 |
| 123125213| 1 |fffff111 |
| 123125213| 1 |fffff111 |
/J
You can use recursive CTE:
WITH RCTE AS
(
SELECT
ordernumber, qty, articlenumber, qty AS L
FROM Table1
UNION ALL
SELECT
ordernumber, 1, articlenumber, L - 1 AS L
FROM RCTE
WHERE L>0
)
SELECT ordernumber,qty, articlenumber
FROM RCTE WHERE qty = 1
SQLFiddleDEMO
EDIT:
Based on Marek Grzenkowicz's answer and MatBailie's comment, whole new idea:
WITH CTE_Nums AS
(
SELECT MAX(qty) n FROM dbo.Table1
UNION ALL
SELECT n-1 FROM CTE_Nums
WHERE n>1
)
SELECT ordernumber ,
1 AS qty,
articlenumber
FROM dbo.Table1 t1
INNER JOIN CTE_Nums n ON t1.qty >= n.n
Generating number from 1 to max(qty) and join table on it.
SQLFiddle DEMO
Here's a quick hack using an additional table populated with a number of rows suitable for the qty values you are expecting:
-- helper table
CREATE TABLE qty_splitter (qty int)
INSERT INTO qty_splitter VALUES (1)
INSERT INTO qty_splitter VALUES (2)
INSERT INTO qty_splitter VALUES (3)
INSERT INTO qty_splitter VALUES (4)
INSERT INTO qty_splitter VALUES (5)
....
-- query to produce split rows
SELECT t1.ordernumber, 1, t1.articlenumber
FROM table1 t1
INNER JOIN qty_splitter qs on t.qty >= qs.qty
You can do it using CTE
declare #t table (ordername varchar(50), qty int)
insert into #t values ('ord1',5),('ord2',3)
;with cte as
(
select ordername, qty, qty-1 n
from #t
union all
select ordername, qty, n-1
from cte
where n>0
)
select ordername,1
from cte
order by ordername
Also you can use option with master..spt_values system table.
SELECT t.ordernumber, o.qty, t.articlenumber
FROM dbo.SplitTable t CROSS APPLY (
SELECT 1 AS qty
FROM master..spt_values v
WHERE v.TYPE = 'P' AND v.number < t.qty
) o
However, for this purpose is preferable to use its own sequence table
See demo on SQLFiddle

recursion in sql server 2005

i Want to genrate possible combination with particluar no in sql server 2005 recursively.
e.g
we Have Main No 2 and Sub no 4,5,6
Combination are
2 4
2 5
2 6
4 5
4 6
5 6
5 2
...........like combination.
Thank u
declare #T table (Num int)
insert into #T values (2)
insert into #T values (4)
insert into #T values (5)
insert into #T values (6)
select
T1.Num as Num1,
T2.Num as Num2
from #T as T1
cross join #T as T2
Insert the numbers in TempTable and use Cross Join
Create Table #LeftTemp
( ID int,
)
Create Table #RightTemp
( ID int,
)
-- Write insert statements
Select * from #LeftTemp CROSS JOIN #RightTemp
;With
List AS (SELECT 2 AS y UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6)
SELECT
*
FROM
List CROSS JOIN list
You'd generate list from your tables

select a set of values as a column without CREATE

I'm trying to write a query that will return all QUERY_ID values alongside all matching TABLE_ID values, where QUERY_ID is not specified in any table, and I can't create tables, so have to specify it in the query itself:
QUERY_ID TABLE_ID
1 1
2 NULL
3 3
4 4
5 NULL
I feel like there ought to be a simple way to do this, but I can't think of it for the life of me. Any help would be wonderful. Thanks!
select q.QUERY_ID, t.TABLE_ID
from (
select 1 as QUERY_ID
union all
select 2
union all
select 3
union all
select 4
union all
select 5
) q
left outer join MyTable t on q.QUERY_ID = t.TABLE_ID
one way by using the built in master..spt_values table
SELECT number AS QUERY_ID,TABLE_ID
FROM master..spt_values v
LEFT JOIN YourTable y ON y.QUERY_ID = y.TABLE_ID
WHERE TYPE = 'p'
AND number > 0
AND number <= (SELECT COUNT(*) FROM YourTable)
order by QUERY_ID
are you able to create #temp tables...can you do this?
create table #temp(QUERY_ID int identity,TABLE_ID varchar(200))
insert #temp(TABLE_ID)
select TABLE_ID
from YourTable
select * from #temp
order by QUERY_ID
drop table #temp
or like this
select identity(int,1,1) as QUERY_ID,TABLE_ID
into #temp
from YourTable
select * from #temp
order by QUERY_ID
On sql server 2005 and up there is the row_number function so maybe a reason to upgrade :-)