I have a table currently only two columns because I am learning, the first column is the Book_skey and this is generated automatically by the system using the IDENTITY function, however what I would like to do in the second coloumn is create a automated field called BookRef where the first row will be B00000001 the next row will be B00000002 etc.
USE Occupancy
DECLARE #BookNumber INT
SET #BookNumber = 1
WHILE #BookNumber <= 5000
BEGIN
INSERT INTO Book(BookNumber)
SELECT #BookNumber
SET #BookNumber = #BookNumber + 1
END
Can this be done?
Thanks
Wayne
You just need to use a computed column.
CREATE TABLE Book (
Book_skey int IDENTITY(1,1)
,BookRef as ('B' + RIGHT(CONVERT(CHAR(9), (100000000 + BookNumber)),8))
,BookNumber int
)
SET NOCOUNT ON
DECLARE #BookNumber INT
SET #BookNumber = 1
WHILE #BookNumber <= 5000
BEGIN
INSERT INTO Book(BookNumber)
SELECT #BookNumber
SET #BookNumber = #BookNumber + 1
END
SELECT * FROM Book
Related
This is redshift. I have an update command that looks like this:
UPDATE users
SET birthday = temp_users.birth_date
FROM public.users as gpu
INNER JOIN temp_schema.users_birth_dates_with_row_numbers AS temp_users ON gpu.id = temp_users.id
WHERE mod(temp_users.row_id, 10) = 0 -- this is what I want to change from 0 -> 9
;
For context: I want to run this time times with a different modulo number. How can I do this? Row id is basically created with the row_number function and I want to do this in batches so that it doesn't hold any locks for too long.
SQL WHILE loop syntax and example
The syntax of the WHILE loop in SQL looks like as follows:
WHILE condition BEGIN {...statements...} END
Example:
DECLARE #Counter INT
SET #Counter=0
WHILE ( #Counter <= 9)
BEGIN
PRINT 'The counter value is = ' + CONVERT(VARCHAR,#Counter)
SET #Counter = #Counter + 1
END
This nested while loop is only successfully executing the lowest level loop. It refuses to add 1 to #wKey even though I tell it to SET #wKey = #wKey + 1.... What am I doing wrong here? Does SQL not allow nested loops?
DECLARE #fMinKey INT;
DECLARE #fMaxKey INT;
DECLARE #wMaxKey INT;
DECLARE #wKey INT;
DECLARE #wDate date;
DECLARE #fcStart DATE;
SET #fMinKey = (select min([fcKey]) from dbo.fact_Fc);
SET #fMaxKey = (select max([fcKey]) from dw.fact_Fc);
SET #wMaxKey = (select max([WellKey]) from dw.fact_Fc);
SET #wKey = 1;
SET #wDate =
(select min([fapDate]) from dbo.dim_W where [Key] = #wKey);
SET #fcStart =
(select min([Date]) from dw.fact_Fc where [wKey] = #wKey);
WHILE (#fMinKey <= #fMaxKey)
BEGIN
WHILE (#wKey <= #wMaxKey)
BEGIN
WHILE (#wDate < #fcStart)
BEGIN
INSERT INTO dw.fact_FcTemp2 ([wKey], [Date], [pAmount], [fcKey], [AddedDate])
VALUES (#wKey, #wDate, 0, #fMinKey, CURRENT_TIMESTAMP)
SET #wDate = dateadd(DAY, 1, #wDate)
END
SET #wKey = #wKey + 1
END
SET #fMinKey = #fMinKey + 1
END
The resulting table is only showing [wKey] = 1, but it should have rows for multiple different wKeys
Once when #wDate reach #fcStart looks like you never reset #wDate to initial state
So next loop run again
You need some how to reset #wDate for next loop
Also having 3 loops perhaps is miss of design, sql performances does not like loops at all.
Can you show us data structure and needed result maybe tehe is way to constuct sql whitout 3 nested loops
I am using SQL Server 2012. I need to do paging in my stored procedure. In client side (Web page), I need to have the result of the stored procedure for requested page and also I need to have the row count without considering the page number for setting number of page with that condition.
For example, I need to run this stored procedure for querying ten row of second page when my SubscribeId is 12345674.
Create Procedure TestSelectBill
(#PageNumber int = 1 ,
#RowCount int = 10 ,
#SubscribeId Int = 0)
As
Begin
Select *
From billing.BillMaster As BM
Where (Bm.SubscribeId = #SubscribeId)
Order by SubscribeId
Offset (#PageNumber - 1) * #RowCount Rows
Fetch Next #RowCount Rows Only;
End
I have to execute this stored procedure like this :
Execute TestSelectBill
#PageNumber = 2, #RowCount int = 10, #SubscribeId = 12345674
Imagine, that I have 105 rows in billing.BillMaster for this SubscribeId = 123456574. Now I need to show 10 row to my end user as result and I have to let him to select one page between 1 to 11.
That means I need to know how many row is exist for this condition SubscribeId = 123456574.
I can change my stored procedure like the below code to return row count:
Create Procedure TestSelectBill
(#PageNumber int = 1,
#RowCount int = 10,
#SubscribeId Int = 0)
As
Begin
DECLARE #ROW_COUNT INT = 0
-- Find Row Count for this condition
Select
#ROW_COUNT = COUNT(*)
From
billing.BillMaster As BM
Where
(Bm.SubscribeId = #SubscribeId)
-- Select Result
SELECT
Row_Count = #ROW_COUNT,
*
FROM
billing.BillMaster As BM
WHERE
(Bm.SubscribeId = #SubscribeId)
ORDER BY
SubscribeId
OFFSET ( #PageNumber - 1 ) * #RowCount ROWS
FETCH NEXT #RowCount ROWS ONLY;
End
But as you see I have to write my select two times and it is not good because modification and maintenance of this stored procedure will be very complicated.
Also, I can save my result into temp table and then use that like the below code:
CREATE Procedure TestSelectBill
(#PageNumber int = 1,
#RowCount int = 10,
#SubscribeId Int = 0)
As
Begin
DECLARE #ROW_COUNT INT = 0
-- Main Select
SELECT
*
FROM
billing.BillMaster As BM
INTO
#T
WHERE
(Bm.SubscribeId = #SubscribeId)
-- Find Row Count for this condituion
SELECT #ROW_COUNT = COUNT(*)
FROM #T
-- Select Result
SELECT
Row_Count = #ROW_COUNT,
*
FROM
#T
ORDER BY
SubscribeId
OFFSET (#PageNumber - 1) * #RowCount ROWS
FETCH NEXT #RowCount ROWS ONLY;
End
But as you can see in this way, I am using physical temp table that can be very slow when I have a lot of data in main select with out paging.
Can anyone tell me the best way to do that?
-- First solution use count with window function
CREATE Procedure TestSelectBill
(#PageNumber int = 1,
#RowCount int = 10,
#SubscribeId Int = 0)
As
Begin
SELECT
COUNT(*) OVER(ORDER BY (SELECT NULL)) AS row_count ,
*
FROM
billing.BillMaster As BM
WHERE
(Bm.SubscribeId = #SubscribeId)
ORDER BY
SubscribeId
OFFSET (#PageNumber - 1) * #RowCount ROWS
FETCH NEXT #RowCount ROWS ONLY;
End
GO
-- Second solution: use dynamic sql with multiple result
Create Procedure TestSelectBill
#PageNumber int = 1,
#RowCount int = 10,
#SubscribeId Int = 0
As
Begin
DECLARE #params NVARCHAR(max) = '#PageNumber int, #RowCount int, #SubscribeId int'
DECLARE #where NVARCHAR(max) = N' WHERE Bm.SubscribeId = #SubscribeId'
DECLARE #stmt NVARCHAR(max) = N'SELECT COUNT(*) as row_cnt FROM billing.BillMaster As BM '
DECLARE #stmt_rowcount NVARCHAR(max) = N'SELECT * FROM billing.BillMaster As BM '
DECLARE #order_by NVARCHAR(max) = ' ORDER BY SubscribeId
OFFSET (#PageNumber - 1) * #RowCount ROWS
FETCH NEXT #RowCount ROWS ONLY;'
SET #stmt += #where + #order_by
SET #stmt_rowcount += #where
-- First result set (rowcount)
EXEC [sys].[sp_executesql]
#stmt = #stmt_rowcount,
#params = #params,
#SubscribeId = #SubscribeId,
#PageNumber = #PageNumber,
#RowCount = #RowCount
-- Second result set (data)
IF ##ERROR = 0
BEGIN
EXEC [sys].[sp_executesql]
#stmt = #stmt,
#params = #params,
#SubscribeId = #SubscribeId,
#PageNumber = #PageNumber,
#RowCount = #RowCount
END
End
GO
You could create a temp table with an identity column that increments by 1 for each row inserted, then read the max value of that column to get the row count.
I am trying to set individual columns of a table variable iteratively as follows:
declare #reg_data table
(
I int NOT NULL PRIMARY KEY IDENTITY,
Y float
)
declare #counter int, #numRows int
SET #counter = 0
SET #numRows = (select MAX(val) + 10 from tableY)
WHILE #counter < numRows
BEGIN
SET #reg_data.Y = dbo.func1(#counter) --HOW DO I DO THIS!!!
#counter = #counter + 1
END
The above does not work because you cannot access table variables like an array. How can I obtain the following functionality?
You can't set values in records that doesn't exists, so you need an insert:
WHILE #counter < numRows
BEGIN
INSERT INTO #reg_data (Y) values (dbo.func1(#counter))
#counter = #counter + 1
END
Just for the completeness a one-statement example with a CTE and no looping:
DECLARE #reg_data TABLE (
I INT NOT NULL PRIMARY KEY IDENTITY,
Y FLOAT
);
WITH cteNum AS (
SELECT MAX(val) + 10 AS val
FROM #tableY
HAVING MAX(val) >= 0
UNION ALL
SELECT val-1
FROM cteNum
WHERE val > 0
)
INSERT #reg_data(Y)
SELECT dbo.func1(val)
FROM cteNum
OPTION (MAXRECURSION 0);
Why use a cursor for this at all??
Why don't you just write some UPDATE statements:
WHILE #counter < numRows
BEGIN
UPDATE #reg_data
SET Y = dbo.func1(#counter)
WHERE I = #counter
SET #counter = #counter + 1
END
You need to somehow be able to read out the identifying values (the I) from the table variable, so you can use that in your UPDATE statement to apply the update to exactly one row (that's identified by that value of I)
I can:
declare #idOrder int
set #idOrder = 21319
I want:
declare #idOrder int
set #idOrder = (21319, 21320)
for use in a series of statements where the 'WHERE' clause uses the IN operator
delete Orders
where idOrder in #idOrder
instead of
delete Orders
where idOrder in (21319, 21320)
You can't do that as long as it's an int, as that's not a valid value for that datatype. A datatype that could take several integers is a table
declare #idOrder table (id int)
insert into #idOrder values(21319)
insert into #idOrder values(21320)
delete from Orders where idOrder in (select id from #idOrder)
In SQL Server you can also
CREATE FUNCTION [dbo].[fn_ado_param_int] (#ado nvarchar(4000))
RETURNS #VALUES TABLE (ado int)AS
BEGIN
declare #Delim char(1)
set #Delim = ','
DECLARE #chrind INT
DECLARE #Piece nvarchar(4000)
SELECT #chrind = 1
WHILE #chrind > 0
BEGIN
SELECT #chrind = CHARINDEX(#Delim,#ado)
IF #chrind > 0
SELECT #Piece = LEFT(#ado,#chrind - 1)
ELSE
SELECT #Piece = #ado
INSERT #VALUES(ado) VALUES(#Piece)
SELECT #ado = RIGHT(#ado,LEN(#ado) - #chrind)
IF LEN(#ado) = 0 BREAK
END
RETURN
END
declare #idOrder varchar(500);
set #inOrder = "21319,2138,2138";
delete from Orders where id in (select ado from dbo.fn_ado_param_int(#idOrder));