SQL Server: Column with 100 rows organized by repeating A-Z? - sql

I am looking to create a table that has 100 rows, and the first column is organized by the letters A-Z, and repeats all the way to 100. The closest I have come is either:
having a numeric column that then uses the ASCII values to convert the number to the letter, however this involves creating the numeric column first, and then having the alphabet column dependent on this one, or
I have been able to create a single column, however when I try to print the whole table, it shows up as AAAA, BBBB, CCCC, DDDD, etc.
I need the column to be completely independent which is why solution #1 doesn't work, and I can't find a way to properly sort or organize solution #2 for it to be A, B, C instead of the way it is printing now. Screenshots for context:
Solution 1
Solution 2
I have been using this code to create the table:
SELECT n
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)
)
SELECT n1.n + n10.n * 10 as col
INTO dbo.table1
FROM nums n1
CROSS JOIN nums n10;
Then for solution 1, I tried this:
ALTER TABLE numbers
ADD letters AS CHAR(num % 26 + 65);
SELECT * FROM numbers
ORDER BY num;
and for solution 2, this:
ALTER TABLE table1
ALTER COLUMN col VARCHAR(3);
UPDATE table1
SET col = col % 26 + 65;
UPDATE table1
SET col = CHAR(col);
SELECT * FROM table1
ORDER BY col;
I have been at this for a few hours now, trying different things in both solutions to get the answer.
Thanks in advance.

If you want to repeatedly cycle through generating letters, you can use a recursive CTE:
with cte as (
select convert(varchar(max), 'A') as letter, 1 as n
union all
select (case when letter < 'Z' then convert(varchar(max), char(ascii(letter) + 1)) else 'A' end),
n + 1
from cte
where n < 100
)
select letter
from cte;
You can use insert or select into to put the values in a table.
If you want more than 100 rows, you'll need to add option (maxrecursion 0).

There is no certain order of rows in a table. Even if the table has a clustered index specified. Such a concept does not exist in relational databases.
To ensure a specific order of values you need to force it using ORDER BY clause in a SELECT statement.
Considering that, the following code must give you an idea how to implement your solution:
With nums as (
SELECT n
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)
),
numbers as (
SELECT n1.n + n10.n * 10 as num
FROM nums n1
CROSS JOIN nums n10
)
select num, char(num/26 + 65) + CHAR(num % 26 + 65)
from numbers
order by num

Related

How to add specific number of empty rows in sqlite?

I have a SQLite file and I want to add 2550 empty (NULL) rows.
I am able to add one empty line with this code
INSERT INTO my_table DEFAULT VALUES
But I need 2550 rows. Is there any shortcut for it? I don't want to execute same code 2550 times.
If your version of SQLite support it, you could use a recursive CTE to generate a series from 1 to 2550, and then insert "empty" records along that sequence:
WITH RECURSIVE generate_series(value) AS (
SELECT 1
UNION ALL
SELECT value + 1
FROM generate_series
WHERE value + 1 <= 2550
)
INSERT INTO yourTable (col1, col2, ...)
SELECT NULL, NULL, ...
FROM generate_series;
It is not clear which values, if any, you want to specify for the actual insert. If you omit mention of any column in the insert, then by default SQLite should assign NULL or whatever default value be defined for that column.
If your table is empty, then use a recursive CTE to get 2550 rows each consisting of the integers 1 to 2550 and use them to insert 2550 rows:
WITH cte AS (
SELECT 1 nr
UNION ALL
SELECT nr + 1
FROM cte
WHERE nr < 2550
)
INSERT INTO my_table(rowid)
SELECT nr FROM cte
This way, you use the column rowid where the integer values of the CTE will be stored and there is no need to enumerate all the columns of your table in the INSERT statement. These columns will get their default values.
If your table is not empty you can do it in a similar way by starting the integer numbers from the max rowid value in the table +1:
WITH cte AS (
SELECT MAX(rowid) + 1 nr FROM my_table
UNION ALL
SELECT nr + 1
FROM cte
WHERE nr < (SELECT MAX(rowid) + 2550 FROM my_table)
)
INSERT INTO my_table(rowid)
SELECT nr FROM cte
See a simplified demo (for 5 rows).
But since you also tagged android-sqlite you can use a for loop:
for (int i = 1; i <= 2550; i++) {
db.execSQL("INSERT INTO my_table DEFAULT VALUES");
}
where db is a valid non null instance of SQLiteDatabase.
You can generate numbers using a recursive CTE and then insert . . . but you need to be more explicit about the values being inserted:
with cte as (
select 1 as n
union all
select n + 1
from cte
where n < 2550
)
insert into mytable (<something>)
select <something>
from cte;
I think you need to specify the value for at least one column in SQLite.

How to generate 6 digit unique alphanumeric string with 6- character length, case nonsensitive for 4 million records. By replacing

How to generate 6 digit unique alphanumeric string with 6- character length, case nonsensitive for 4 million records. By replacing 1’s, I’s, O’s, and 0’s.
I have tried using the below query but the problem is when I am trying to replace the above values the unique id has some duplicate values.
**
select CAST(REPLACE(REPLACE(CHAR( ASCII('AA')+(ABS(CHECKSUM(NEWID()))%25)) , 'O', ''), 'I', '')
REPLACE(REPLACE(REPLACE( REPLACE(SUBSTRING(CONVERT(varchar(60), NEWID()),1, 10) , '-',''), '.' , ''), '0' , ''), '1','') AS nvarchar (6))
, employee_id
from cte
**
The final output should be something like:
....
....
....
...
....
....
....
...
....
....
...
How to generate 6 digit unique alphanumeric string with 6- character length, case nonsensitive for 4 million records.
There are enough hex digits to do what you want. So, one option is:
select right('ZZZZZZ' + format(row_number() over (order by newid()), 'X'), 6)
This generates a sequential number (randomly), converts it to hex, and then prepends Zs.
If you want the UIDs to appear to be random (e.g., 1st could be G5K2M5, second 23BN32, etc), I think you basically have three choices
(In a loop) randomly generating UIDs, remove those that a) already exist, and b) have duplicates in your generated list, then insert the unique UIDs. Repeat until you have none left.
Generate a table with all possible UIDs (e.g., all letters and numbers except 1, I, L, 0, o - note I've added L to the list as lowercase l looks like I or 1). That means 31 possible characters in 6 slots... 31^6 is approximately 900 million possibilities. For the UIDs to use, randomly select the number needed from the UID list, assign them as needed, then remove them from the list so you won't get doubles.
Use a formula where each number is uniquely mapped to a UID. Then just get the rownumber or other unique int identifier, and calculate the UID from it. Note that the formula could be a mathematical formula, or could just be a table (as above) where the UIDs are initially randomly sorted, and you just take the UID from the relevant rownumber.
select top (100000)
cte.*,
concat
(
substring(s.random32, p.p1, 1),
substring(s.random32, p.p2, 1),
substring(s.random32, p.p3, 1),
substring(s.random32, p.p4, 1),
substring(s.random32, p.p5, 1),
substring(s.random32, p.p6, 1)
) as combo6
from
--employees
(
--4mil employees
select top (4000000)
row_number() over(order by ##spid) as empid, --this could be empid, eg. empid as n
a.name as empfirstname, a.name as emplastname, b.type_desc as emptype
from sys.all_objects as a
cross join sys.all_objects as b
) as cte
--random string
cross join
(
--one random string (excluding 1, 0, I, O)
select top (1)
(
select v.v as '*'
from
(values
('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),
('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),
('J'),('K'),('L'),('M'),('N'), ('P'),('Q'),('R'),
('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')
) as v(v)
order by newid()
for xml path('')
) as random32
) as s
--combo6 positions in string
cross apply
(
select
/*for 32 chars = len(rand32) */
(power(32,0)+(cte.empid-1)%power(32, 1))/power(32,0) as p1,
(power(32,1)+(cte.empid-1)%power(32, 2))/power(32,1) as p2,
(power(32,2)+(cte.empid-1)%power(32, 3))/power(32,2) as p3,
(power(32,3)+(cte.empid-1)%power(32, 4))/power(32,3) as p4,
(power(32,4)+(cte.empid-1)%power(32, 5))/power(32,4) as p5,
(power(32,5)+(cte.empid-1)%power(32, 6))/power(32,5) as p6
) as p
go
....or....(?)
create or alter function dbo.[why?]()
returns char(6)
as
begin
declare #combo6 char(6);
declare #randomstring char(32) = cast(session_context(N'randomstring') as char(32));
if #randomstring is null
begin
select #randomstring =
(
select v.v as '*'
from
(values
('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),
('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),
('J'),('K'),('L'),('M'),('N'), ('P'),('Q'),('R'),
('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')
) as v(v)
order by checksum(##idle, ##cpu_busy, (select max(last_request_end_time) from sys.dm_exec_sessions where session_id=##spid), v.v)
for xml path('')
);
end
declare #randomnumber int = 1 + isnull(cast(session_context(N'randomnumber') as int), abs(checksum(#randomstring))%10000000);
select #combo6 = concat(
substring(#randomstring, p.p1, 1),
substring(#randomstring, p.p2, 1),
substring(#randomstring, p.p3, 1),
substring(#randomstring, p.p4, 1),
substring(#randomstring, p.p5, 1),
substring(#randomstring, p.p6, 1)
)
from
(
select
/*for 32 chars = len(rand32) */
(power(32,0)+(#randomnumber-1)%power(32, 1))/power(32,0) as p1,
(power(32,1)+(#randomnumber-1)%power(32, 2))/power(32,1) as p2,
(power(32,2)+(#randomnumber-1)%power(32, 3))/power(32,2) as p3,
(power(32,3)+(#randomnumber-1)%power(32, 4))/power(32,3) as p4,
(power(32,4)+(#randomnumber-1)%power(32, 5))/power(32,4) as p5,
(power(32,5)+(#randomnumber-1)%power(32, 6))/power(32,5) as p6
) as p;
exec sp_set_session_context #key=N'randomstring', #value=#randomstring;
exec sp_set_session_context #key=N'randomnumber', #value=#randomnumber;
return(#combo6);
end
go
exec sp_set_session_context #key=N'randomstring', #value=null;
exec sp_set_session_context #key=N'randomnumber', #value=null;
go
select top (100000) dbo.[why?]() as empid, a.name, b.object_id
from sys.all_objects as a
cross join sys.all_objects as b
go
--drop function dbo.[why?]
The difficulty reside on the UNIQUE feature of the string. Some solutions that have been shown cannot guarantee the uniqueness of the generated strings.
First solution of lptr does not give always 6 letters and give some duplicates.
My solution give the full requirement, but it is slow :
WITH TAZ AS
(SELECT CAST('A' COLLATE Latin1_General_BIN AS CHAR(1)) AS LETTER, ASCII('A') AS CAR
UNION ALL
SELECT CAST(CHAR(CAR + 1) COLLATE Latin1_General_BIN AS CHAR(1)), CAR + 1
FROM TAZ
WHERE CHAR(CAR + 1) <= 'Z'
)
SELECT TOP 4000000
T1.LETTER + T2.LETTER + T3.LETTER + T4.LETTER + T5.LETTER + T6.LETTER AS L6
FROM TAZ AS T1
CROSS JOIN TAZ AS T2
CROSS JOIN TAZ AS T3
CROSS JOIN TAZ AS T4
CROSS JOIN TAZ AS T5
CROSS JOIN TAZ AS T6
ORDER BY NEWID()
One thing I do in such a case is to compute all the 6 length strings possible and store it in a plain table stored in a compressed mode and in a read only storage (a tally table). The table has an ID and an extra column of bit type with the 0 value.
When you want to attribute some 6 chars string values, you just pickup from the table and marks it with the bit modify to 1.
As an information, this is the way that referenced ticket file are givent to customer in the french national railway compagny call SNCF since a long time.
First, let me start by saying you already have some fine answers here, the only problem is with them is that they are slow. My suggested solution is fast - even very fast in comparison.
A year ago I've written a blog post entitled How to pre-populate a random strings pool
that was based on an answer written by Martin Smith to How can I generate random strings in TSQL. I've basically took the code posted in that answer and wrapped it up inside a inline table valued function.
For this problem, I've taken that function and modified it ever so slightly to better fit your requirements - mainly the number of random strings (original version can produce up to 1,000,000 rows only) and the case-insensitivity.
Tests I've made comparing the speed of execution between Gordon's SQLpro's, lptr's answers and my own showed conclusively that this is the best solution between all four, at least in terms of execution speed.
So, without further ado, here's the code:
First, the function and it's auxiliary view:
-- This view is needed for the function to work. Read my blog post for details.
CREATE VIEW dbo.GuidGenerator
AS
SELECT Newid() As NewGuid;
GO
-- slightly modified version to enable the generation of up to 100,000,000 rows.
CREATE FUNCTION dbo.RandomStringGenerator
(
#Length int,
#Count int -- Note: up to 100,000,000 rows
)
RETURNS TABLE
AS
RETURN
WITH E1(N) AS (SELECT N FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) V(N)), -- 10
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --100
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10,000
Tally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY ##SPID) FROM E4 a, E4 b) -- 100,000,000
SELECT TOP(#Count)
N As Number,
(
SELECT TOP (#Length) CHAR(
CASE Abs(Checksum(NewGuid)) % 2
WHEN 0 THEN 65 + Abs(Checksum(NewGuid)) % 26 -- Random upper case letter
ELSE 48 + Abs(Checksum(NewGuid)) % 10 -- Random digit
END
)
FROM Tally As t0
CROSS JOIN GuidGenerator
WHERE t0.n <> -t1.n
FOR XML PATH('')
) As RandomString
FROM Tally As t1
GO
Then, using distinct, top 4000000 and a simple where clause - select the random strings you want:
SELECT DISTINCT TOP 4000000 Number, RandomString
FROM dbo.RandomStringGenerator(6,100000000)
WHERE RandomString NOT LIKE '%[IiOoLl01]%' -- in case your database's default collation is case sensitive...
The reason this is the fastest solution is very simple - My solution already generates the strings randomly, so I don't need to also sort them randomly - which is the biggest bottle neck of the other suggested solutions.
If you don't need the order to be random, you can go with SQLpro's solution, just remove the order by newid() - that was the fastest solution (though it didn't filter out the unwanted chars)
Update
As requested by lptr - here's an example on how to select the random strings and another table as well:
WITH Tbl AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Em_Id) As Rn
FROM <TableNameHere>
), Rnd AS
(
SELECT DISTINCT TOP 4000000 ROW_NUMBER() OVER (ORDER BY Number) As Rn, RandomString
FROM dbo.RandomStringGenerator(6,100000000)
WHERE RandomString NOT LIKE '%[IiOoLl01]%'
)
SELECT Em_Id, RandomString
FROM Tbl
INNER JOIN rnd
ON Tbl.Rn = Rnd.Rn
Notes:
Change <TableNameHere> to the actual table name
You can use any column (or constant) for the order by of the row number, it doesn't matter because the order is irrelevant here anyway.

Select or print column values that don’t exist between two integers

I have a list of about 10k sequential integer values that were supposed to be inserted into a table column from an external application. However, doing a COUNT() reveals that only 9900 were inserted.
I need to determine which of the numbers in the sequence were NOT inserted.
Using it the other way around is easy, just select from table column where value is BETWEEN x AND y, but I haven't figured out how to print (or select) the values that don't exist in the table column.
EDIT: remove extranous '' from integers below
SELECT * FROM table
WHERE column1 = 'value'
AND column2 BETWEEN 1 AND 10000
How can I print the value from the BETWEEN clause where column2 doesn't have value in range?
You could do something like:
select level num
from dual
connect by level <= 10000
minus
select column2
from your_table;
You may need to do to_char(level) if your column2 is a varchar2 column.
You need to use a source of numbers. If this table is your only data, you can use it:
with n as (
select rownum as n
from t cross join
(select 1 from dual union all select 2 from dual) x
)
select n.n
from n left join
t
on n.n = t.column2 and t.column1 = 'value'
where n <= 10000;
The calculation for n assumes that your table has at least 5,000 rows. If it has more than 10,000 then x is not necessary.

create a table of duplicated rows of another table using the select statement

I have a table with one column containing different integers.
For each integer in the table I would like to duplicate it as the number of digits -
For example:
12345 (5 digits):
1. 12345
2. 12345
3. 12345
4. 12345
5. 12345
I thought doing it using with recursion t (...) as () but I didn't manage, since I don't really understand how it works and what is happening "behind the scenes.
I don't want to use insert because I want it to be scalable and automatic for as many integers as needed in a table.
Any thoughts and an explanation would be great.
The easiest way is to join to a table with numbers from 1 to n in it.
SELECT n, x
FROM yourtable
JOIN
(
SELECT day_of_calendar AS n
FROM sys_calendar.CALENDAR
WHERE n BETWEEN 1 AND 12 -- maximum number of digits
) AS dt
ON n <= CHAR_LENGTH(TRIM(ABS(x)))
In my example I abused TD's builtin calendar, but that's not a good choice, as the optimizer doesn't know how many rows will be returned and as the plan must be a Product Join it might decide to do something stupid. So better use a number table...
Create a numbers table that will contain the integers from 1 to the maximum number of digits that the numbers in your table will have (I went with 6):
create table numbers(num int)
insert numbers
select 1 union select 2 union select 3 union select 4 union select 5 union select 6
You already have your table (but here's what I was using to test):
create table your_table(num int)
insert your_table
select 12345 union select 678
Here's the query to get your results:
select ROW_NUMBER() over(partition by b.num order by b.num) row_num, b.num, LEN(cast(b.num as char)) num_digits
into #temp
from your_table b
cross join numbers n
select t.num
from #temp t
where t.row_num <= t.num_digits
I found a nice way to perform this action. Here goes:
with recursive t (num,num_as_char,char_n)
as
(
select num
,cast (num as varchar (100)) as num_as_char
,substr (num_as_char,1,1)
from numbers
union all
select num
,substr (t.num_as_char,2) as num_as_char2
,substr (num_as_char2,1,1)
from t
where char_length (num_as_char2) > 0
)
select *
from t
order by num,char_length (num_as_char) desc

how to enter series of numbers in a table column

I want to have values in a column in particular series
10100
10200
10300
.
.
.
.
11000
11100
11200
.
.
How to do this ? I think while loop would be used
insert into mytable(col_name)
select <>
You can do this:
WITH Temp
AS
(
SELECT digit
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS temp(digit)
), Nums
AS
(
SELECT t3.digit * 100 + t2.digit * 10 + t1.digit + 1 AS id
FROM TEMP AS t1
CROSS JOIN TEMP AS t2
CROSS JOIN TEMP AS t3
)
SELECT
n = 10100 + (id - 1) * 100
from nums
ORDER BY n;
SQL Fiddle Demo
How this works?
This query will give you 1000 rows for the sequence you are looking for, which is called Arithmetic progression, and in your sequence the nth term of the sequence is given by A + (n - 1) * d. In your sequence: a = 10100 the first number, the starting number, d = 100 which is the seed.
First, I used an anchor query which generate 10 numbers, (note that this syntax is new to SQL Server 2008),
then I cross joined it with itself 3 times giving me 103 rows = 1000 rows I used them to generate 1000 numbers of this sequence based on the rule: each n number = A + (n - 1) * d , if you need more cross join it with it self more times.
You can then insert them into a new table, just do INSERT INTO SELECT, instead of just SELECT.
Note that: You might need to use IDENTITY column instead of all this stuff, using it you can define a starting value and a seeding value, then it will be incremented automatically, see this article:
Understanding Identity Columns
Please try this:
DECLARE #table as TABLE(NUM bigint)
declare #var bigint
set #var=10100
while #var<11200
begin
insert into #table values (#var)
set #var=#var+100
end
select * from #table