Generate random SQL Server 2008 time test data - sql

I am trying to generate a large data set which includes time datatype in SQL Server 2008. I already have some non-time data in a table so I'd like to keep the entire process in T-SQL and use an insert-into-select to get the partial data from one table and insert it into the next along with some generated data including the time.
I'd like a way to generate random time(7)s between two points, say a random time between 8:00 and 9:00. I've found some pre-2008 post but nothing that addresses SQL Server 2008's time type.

There are 86,400,000 milliseconds in a day, so you can get a random time value by doing this:
select dateadd(millisecond, cast(86400000 * RAND() as int), convert(time, '00:00'))
For your example where you want times between 8:00 and 9:00, there are 3,600,000 milliseconds in an hour, so modify the query like this.
select dateadd(millisecond, cast(3600000 * RAND() as int), convert(time, '08:00'))
In order to put in into your new table, you might either do a T-SQL loop with updates (s...l...o...w...), or do a SELECT INTO from your original table into a new table.

To generate 100 rows of test data you can use the below.
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b)
SELECT TOP 100 CAST(DATEADD(SECOND,ABS(CHECKSUM(NEWID()))%3600,'08:00') AS TIME)
FROM E32

Related

SQL get only unique combination of two columns

I have table with:
A B
1 2
2 1
and i trying using sql command to get only one combination
A B
1 2
how can i do that?
A canonical way in standard SQL is:
select a, b
from t
where a < b
union all
select a, b
from t
where a > b and not exists (select 1 from t t2 where t2.a = t.b and t2.b = t.a);
Note that this assumes no duplicates or equal values. You can easily handle these using select distinct and <= comparisons. In my experience, this problem often arises when there are at most two rows per pair.
This preserves the original values. So, if you start with:
1 2
5 4
You will get that in the result set.
If you don't care about ordering, then many databases support least()/greatest():
select least(a, b) as a, greatest(a, b) as b
from t
group by least(a, b), greatest(a, b);
You can do the same thing with case expressions. Or, more simply as:
select distinct least(a, b) as a, greatest(a, b) as b
from t;

how to mix 2 tables(A,B) in 1 table (AB) with sql (db2 dialog) with special order between records

Please how to mix 2 tables(A,B) in 1 table(AB) with special order.
It is 2 tables, A and B with only 1 col. So it is a list/array.
I must order the row like this:
A.col1,A.col1,B.col1,B.col1,A.col1,A.col1,B.col1,B.col1,A.col1,A.col1,B.col1,B.col1 and so on.
To see it easily, it must be:
A,A,B,B,A,A,B,B,A,A
So 2 row from A, 2 row from B, 2 row from A, 2 row from B and so on
I would prefer with db2 sql dialog language, but if it isnt specific would be useful in any sql dialog
thanks
Try this:
SELECT Field1 FROM
(SELECT Field1, 1 AS S, ROW_NUMBER() OVER() AS N, FLOOR(ROW_NUMBER() OVER()/2) AS G FROM A
UNION ALL
SELECT Field1, 2 AS S, ROW_NUMBER() OVER() AS N, FLOOR(ROW_NUMBER() OVER()/2) AS G FROM B)
ORDER BY G, S, N
That should work in DB2. Unfortunately I don't have a DB2 database handy to test it so the code goes without any warranty.

Availability in a reservation database

I have a database for hotel reservation with tables: room, customer, reservation (id, id_room, id_customer_ arrive_date, departure_date, ...).
When I select a room in my app I need to view a calendar widget with days red colored if in that day the room is busy.
I need a way to retrieve a list of busy days for a room,month,year combination.
My idea is to create a new table from previous with columns: date,day,month,year,room,is_busy and then query it.
SELECT day FROM new_table WHERE month=m AND year=y AND room=r AND is_busy=1
The problem is to update the new table every time.
Is there a simple way?
You can try this script. It will return busy dates for each room for next 255 days from now.
SELECT * INTO reservation
FROM (VALUES (1, 1, '2016-07-03','2016-07-06'),(2, 2, '2016-07-10','2016-07-15'))
a(CustomerID, RoomID, arrive_date, departure_date);
GO
;WITH Pass0 as (select 1 as C union all select 1),
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),
FutureDates(FutureDates) as (SELECT DATEADD(DAY,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1, CAST(GETDATE() AS DATE)) FROM Pass3)
SELECT r.RoomID, f.FutureDates as BusyDate
FROM reservation as r
INNER JOIN FutureDates as f
ON f.FutureDates >= r.arrive_date and f.FutureDates < r.departure_date;

SQL Query to fetch numbers in given steps between a range

I have a set of data like this:
MinNo: 2500
MaxNo: 2700
IncrementStep: 10
Between the minimum number and the maximum number a list of all possible numbers with the given step are to be listed as shown below:
2500
2510
2520
2530
2540
2550
2560
2570
2580
2590
2600
2610
2620
2630
2640
2650
2660
2670
2680
2690
2700
I'm aware that this can be achieved using a while loop. Kindly let me know if this can be done using a select query using Common Table Expressions (if needed). Thanks in advance.
You can use a numbers table (or master..spt_values).
declare #MinNo int
declare #MaxNo int
declare #IncrementStep int
set #MinNo = 2500
set #MaxNo = 2700
set #IncrementStep = 10
select #MinNo + Number * #IncrementStep
from master..spt_values
where type = 'P' and
number between 0 and (#MaxNo - #MinNo) / #IncrementStep
Or a recursive CTE
;with C as
(
select #MinNo as Num
union all
select Num + #IncrementStep
from C
where Num < #MaxNo
)
select Num
from C
See this useful function
CREATE FUNCTION [dbo].[Sequence](#min INT, #max INT, #step INT)
RETURNS #ret TABLE (id INT PRIMARY KEY)
AS
BEGIN
WITH numbers(id) as
(
SELECT #min id
UNION ALL
SELECT id+#step
FROM numbers
WHERE id < #max
)
INSERT #ret
SELECT id FROM Numbers
OPTION(MAXRECURSION 0)
RETURN
END
#Mikael Eriksson already mentioned a numbers table / tally table (search for it online, there are LOTS of possible uses, many DBAs always want a tally table to be present in any system they manage)
I just wanted to share one non-recursive CTE-based "tally table" solution that I saw online the other day, that I think it amazingly elegant for its huge range (4 thousand million logical rows) and general applicability without any database dependencies:
WITH
E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT *
FROM cteTally
WHERE N >= 2500
AND N <= 2700
AND N % 10 = 0
I found it here, but I don't know whether that's the original source of this CTE.
The nice thing about it is that you don't need to worry about min, max, or step size, and yet it performs very well in most (one-off) situations. That said, it should NOT be used in any frequently-called business process; Any physical indexed numbers table will always perform better!
EDIT: I just searched a little more for the source of this method (I had missed the stackoverflow link in the article I referenced), and apparently it's originally attributed to Itzik Ben-Gan, from the bottom of page 255 in a book titled "Inside Microsoft SQL Server 2005 - T-SQL Querying" (says Jeff Moden, who I implicitly trust).

Generating a sequence in sql server

I am working on a function that will take a low number and a high number as paramaters and returns a table containing everything between (and including).
I know I could use a cursor and increment a variable adding it to a scope based table every iteration, but I would prefer to avoid a cursor if possible. Does anyone else have a suggestion for a way to do this? (As i'm typing this im thinking possibly a CTE, which I will go investigate).
Yes, you can use a recursive CTE to do this. For example to generate numbers between 10 and 20 inclusive:
WITH f AS
(
SELECT 10 AS x
UNION ALL
SELECT x + 1 FROM f WHERE x < 20
)
SELECT * FROM f
Just create an indexed permanent auxiliary numbers table and be done with it. This will out perform any other method.
See Jeff Moden's answer here for more details and a script to populate such a table. if for some reason that isn't an option this should beat the recursive CTE according to the performance tests in the linked answer.
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT N FROM cteTally
WHERE N BETWEEN 10 AND 20