Find missing numerical values in range [duplicate] - sql

This question already has answers here:
How can we find gaps in sequential numbering in MySQL?
(16 answers)
Closed 8 years ago.
I've read several articles that one of the mistakes a common programmer does is not using SQL's potential and since then I started searching for replacing parts of my code with SQLish solutions rather than fetching data and processing with a programming language, although I'm a real rookie with SQL.
Say I have a table randomly populated with values from 0 to 10 and I want to know which values are missing in this range.
For example, the table consists these values: 0, 1, 3, 4, 5, 7, 8, 9.
The query should return: 2, 6, 10.

[F5] solution (assuming sql server):
-- table with id=0..10
drop table #temp
GO
create table #temp (
id int not null identity(0,1),
x int
)
GO
insert into #temp (x) values(0)
GO 11
-- your number:
drop table #numbers
GO
select
*
into #numbers
from (
select 0 as n union all select 1 union all select 3 union all select 4 union all select 5 union all select 7 union all select 8 union all select 9
) x
GO
-- result:
select
*
from #temp t
left join #numbers n
on t.id=n.n
where 1=1
and n.n is null

This solution uses SQL-Server-Syntax (but AFAIK only GO is specific to the SQL Server Management Studio)
I would join against a table valued function that gets you all numbers in a certain range (example fiddle):
CREATE FUNCTION dbo.GetNumbersInRange(#Min INT, #Max INT)
RETURNS #trackingItems TABLE (Number INT)
AS BEGIN
DECLARE #counter INT = #Min
WHILE (#counter <= #Max)
BEGIN
INSERT INTO #trackingItems (Number) SELECT #counter
SELECT #counter = #counter + 1
END
RETURN
END
GO
As an example I have set up a table that contains some numbers (with gaps)
CREATE TABLE MyNumbers (Number INT)
INSERT INTO MyNumbers (Number)
SELECT 1
UNION
SELECT 2
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 7
UNION
SELECT 8
To find the missing numbers you can use a LEFT JOIN like this
SELECT
AllNumbers.Number
FROM GetNumbersInRange(1, 10) AS AllNumbers
LEFT JOIN MyNumbers ON AllNumbers.Number = MyNumbers.Number
WHERE MyNumbers.Number IS NULL

Related

Moving calculations using SQL

I need to calculate a new column using moving calculations.
For example, I have a table:
A
B
10
15
11
14
12
13
I need to calculate new column where the 1st value is calculated like 5000/10*15, the 2nd value is (5000 / 10 * 15) / 11 * 14, the 3rd one is ((5000 / 10 * 15) / 11 * 14) / 12 * 13 and so on. Where 5000 is a random value and in the future I will use it like a parameter in a stored procedure.
I know, that in Excel for example we can reffer to the previous calculated cell. How can it be calculated using SQL?
Thank you!
create table #test (A int,B int)
insert into #test values(10,15),(11,14),(12,13)
declare #seed int=5000;
;with temp as (
select A,B,row_number() over(order by a) rn from #test
),
cte as
(
select #seed/A*B calculated,rn from temp where rn=1
union all
select c. calculated/t.A*t.B,t.rn from temp t
join cte c on t.rn=c.rn+1
)
select * from cte
There is a warning in the docs that reads:
If there are multiple assignment clauses in a single SELECT statement,
SQL Server does not guarantee the order of evaluation of the
expressions. Note that effects are only visible if there are
references among the assignments.
It means there is no guarantee that it will evaluate the expression left-to-right. For this code:
declare #a int, #b int;
select #a = 2, #b = #a * 3;
select #a, #b;
The result could be 2, 6 (#a = ... evaluated first) or 2, NULL (#b = ... evaluated first).

select records that one column are numbers close to 10

I have a table with 3 columns.
one of them is [Code]. I have many records on this table.
I want to select records that their [Code] are numbers close to 10 regularly
for example if select records that has [Code]=9 then select records that has [Code] = 8 etc...
This is what I implement based on your though.
If you wish near record or record-id, not value, then you can change only condition a.data to a.rid.
declare #t table (data int)
insert into #t values(1), (2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(50),(51),(52)
declare #value int = 11 , #getDatToValue int = 2
select * from
(
select * , ROW_NUMBER( ) over(order by data) rid
from #t
)
a
where
a.data between (#value - #getDatToValue) and (#value + #getDatToValue)

Populating an empty table with sequential numbers

I have a table which is already truncated (Microsoft SQL 2008). I have to now populate it with sequential numbers up to 50,000 records arbitrary numbers (doesn't mater) up to 7 characters.
Can any one help as to what SQL statement I need to write that will automatically populate the newly empty table with A000001,A0000002,A0000003, etc so that I can sort number the records within the table.
I have approximately 50000 records which I need to sequentially entered and I really don't want to number the column manually via hand editing.
Thanks in advance.
I'd use excel to generate your unique ids using the following:
In A column:
=CONCATENATE($C2, TEXT($B2,"000000"))
In B column put a 1 in the first row and the following code in all subsequent rows:
=SUM($B4 + 1)
In C column:
The letter A
Then just import the excel csv as a table and you'll have all your ids ready to insert into your empty table.
The SQL below loads a table variable up. Just select from it and insert the data into the new table. Certainly not the model of efficiency, but it'll get the job done.
DECLARE #tmp TABLE(
Value NVARCHAR(10)
)
DECLARE #Counter INT=0
DECLARE #Padding NVARCHAR(20)
WHILE #Counter<50000
BEGIN
SET #Counter=#Counter+1
SET #Padding=
CASE LEN(CONVERT(NVARCHAR,#Counter))
WHEN 1 THEN '00000'
WHEN 2 THEN '0000'
WHEN 3 THEN '000'
WHEN 4 THEN '00'
WHEN 5 THEN '0'
ELSE ''
END
INSERT INTO #tmp SELECT 'A' + #Padding + CONVERT(NVARCHAR,#Counter)
END
select * from #tmp
Use Stacked CTE to generate sequential Numbers
;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
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e2 CROSS JOIN e2 AS b), -- 100*100
e4(n) AS (SELECT 1 FROM e3 CROSS JOIN (SELECT TOP 5 n FROM e1) AS b) -- 5*10000
SELECT n = 'A'+right('000000'+
convert(varchar(20),ROW_NUMBER() OVER (ORDER BY n)),7)
FROM e4 ORDER BY n;
Check here for more methods to generate sequential numbers with performance analysis
Use a table with an identity column and populate it. Then update that table to set the alpha value you need as follows:
create table MyTable (
ID int not null identity(1,1),
Alpha varchar(30)
)
truncate table MyTable
begin tran -- makes it run much faster
declare #i int
select #i = 1
while #i < 1000000
begin
insert into MyTable (Alpha) values ('')
select #i = #i + 1
end
commit
update MyTable set Alpha = 'A' + replicate('0', 6 - len(cast(ID as varchar(30)))) + cast(ID as varchar(30))

How to select records testing bits in BINARY column?

I have 2 tables: one of them contains column binary(128), where every bit is some flag. Also I have other table contains list of bit positions which need to check in query.
This is example how I do the query for one bit.
How to do it universally, i.e. to select records testing bits in positions from the second table?
Should it be a function? what?
DECLARE #nByteNum integer
DECLARE #nBitNumInByte integer
DECLARE #nMask integer
DECLARE #nBigBitNum integer
declare #t table(id int not null identity, id1 int, banner binary(128))
declare #bitpositions table(id int not null identity, position int)
insert into #bitpositions(position) values(8)
insert into #bitpositions(position) values(24)
insert into #bitpositions(position) values(30)
insert into #t(id1, banner)
select 1, 0x0
union all
select 1, 0x000100FF
union all
select 1, 0x010200FF
union all
select 10, 0x010208
union all
select 10, 0x000100
union all
select 10, 0x040000
select * from #t
-- This is for one bit
SET #nBigBitNum= 24
SET #nByteNum= #nBigBitNum/8
SET #nBitNumInByte= #nBigBitNum % 8 -- 0,1...6,7
SET #nMask = POWER(2, #nBitNumInByte ) -- 128,64,... 2,1
SET #nByteNum= #nByteNum +1
select * from #t where SUBSTRING(banner, #nByteNum,1)&#nMask=#nMask
Bitwise operations in SQL Server do not work on BINARY data in the way that you are expecting. They work on integer datatypes only as noted on the MSDN page for & (Bitwise AND).
The general syntax for checking bitmasked values in a query is: WHERE {Column} & {BitMaskedValue} = {BitMaskedValue}.
Look at the following examples using your desired scenario of trying to find records that have bit positions 8 and 16 turned on.
-- 24 = 16 + 8
SELECT 24 & 16 -- 16
SELECT 24 & 8 -- 8
SELECT 24 & 17 -- 16
SELECT 24 & 32 -- 0
SELECT 24 & 26 -- 24

How to insert n number of records in a table in a single command

I want to insert 10000 records in a table and i am currently writing this code
in sql server 2005
declare #n decimal(10,0);
set #n = 0;
while ( #n < 10000)
begin
insert into table1 values (#n+1)
set #n = #n + 1
end
in the above code insert command performs 10000 times is there any single command exists to do so.
Also you can use sys objects to your advantage:
INSERT INTO table1(n)
SELECT TOP 10000 ROW_NUMBER() OVER(ORDER BY a.object_id) AS n FROM sys.objects a CROSS JOIN sys.objects b
GO
You could use a CTE to create an in-memory table of 10000 items and use this to insert into your actual table.
;WITH q (n) AS (
SELECT 1
UNION ALL
SELECT n + 1
FROM q
WHERE n < 10000
)
INSERT INTO table1
SELECT * FROM q
OPTION (MAXRECURSION 0)
A quick way (from HERE):
declare #t table (number int)
insert into #t
select 0
union all
select 1
union all
select 2
union all
select 3
union all
select 4
union all
select 5
union all
select 6
union all
select 7
union all
select 8
union all
select 9
insert into numbers
select
t1.number + t2.number*10 + t3.number*100
from
#t as t1,
#t as t2,
#t as t3