SQL Server daily report multiple columns to rows - sql-server

I have a table like:
create table t_daily_total(
Id bigint identity not null,
ReportDay date null,
Value1 decimal(10,2) default 0 null,
Value2 decimal(10,2) default 0 null
...
Valuen decimal(10,2) default 0 null
)
and I want to see it in a format like:
ValueName, [2021-01-01],[2021-01-02], .... [2021-05-05]
Value1, 1, 2, 3.....
Value2, 5, 6, 7...
....
Valuen, 8, 9 10...
Basically see the values by day. I am using SQL Server 2014. I checked into the pivot and unpivot, but still could not make it work. please help. Thanks!

I got it work like this:
[![--- table structure
create table t_daily_grand_total(
Id bigint identity not null,
ReportDay date null,
ValueName varchar(10) null,
Value decimal(10,2) default 0 null
primary key(Id)
)
-- init data
declare #i int = 0
declare #d date = '2021-01-01'
while #i < 50
begin
insert into t_daily_grand_total(ReportDay, ValueName, Value) values
(#d, 'v1',floor(rand()*60) + 20),
(#d, 'v2',floor(rand()*60) + 20),
(#d, 'v3',floor(rand()*60) + 20)
set #i = #i + 1
set #d = dateadd(day,1 , #d)
end
-- source data
select * from t_daily_grand_total
-- the final result
select * from
(select ReportDay, ValueName, Value from t_daily_grand_total) as st
pivot(
sum(Value)
for ReportDay in(\[2021-01-01\],\[2021-01-02\], \[2021-01-04\], \[2021-01-07\])
) as pt][1]][1]

Related

Create SQL Global Temp Table while Dynamically Pivoting Years between a Date Range as Columns

How would I alter the below manual DDL script in a way to instead create the table dynamically? For example I want to create 2 columns (enroll year and disenroll year) for every year between 2017 and the current year (2021) and pivot them. Currently the script will manually create the columns from 2017 until year 2021. What direction should I take to make this dynamic?
I am thinking to use while loop to accomplish this but I'm not quite sure if I'm on the right track or if there was a better way. Next year in 2022 when the script is run it should append [2022] columns. Next next year in 2023 the script should append [2023] columns and so on.
DROP TABLE IF EXISTS ##Enrollment
CREATE TABLE ##Enrollment
(
[ID] VARCHAR(10),
[First_Name] VARCHAR(255) NULL ,
[Middle_Name] VARCHAR(255) NULL,
[Last_Name] VARCHAR(255) NULL,
[Date_of_Birth] DATE NULL,
[2017_Enrollment_Date] DATE NULL,
[2017_Disenrollment_Date] DATE NULL,
[2018_Enrollment_Date] DATE NULL,
[2018_Disenrollment_Date] DATE NULL,
[2019_Enrollment_Date] DATE NULL,
[2019_Disenrollment_Date] DATE NULL,
[2020_Enrollment_Date] DATE NULL,
[2020_Disenrollment_Date] DATE NULL,
[2021_Enrollment_Date] DATE NULL,
[2021_Disenrollment_Date] DATE NULL,
[Begin_Date] DATE NULL,
[End_Date] DATE NULL
)
One way is iterating over years between a max and min, and then iterating over the 2 possible names for your dynamic columns
declare #minyear int = 2017
declare #maxyear int
declare #ddl varchar(max)
declare #i int = 0
if (#maxyear is null) select #maxyear=year(getdate())
drop table if exists ##Enrollment
set #ddl =
'CREATE TABLE ##Enrollment(
[ID] VARCHAR(10)
,[First_Name] VARCHAR (255) NULL
,[Middle_Name] VARCHAR (255) NULL
,[Last_Name] VARCHAR (255) NULL
,[Date_of_Birth] DATE NULL
,[Begin_Date] DATE NULL
,[End_Date] DATE NULL'
while #maxyear >= #minyear
begin
while #i <= 1
begin
set #ddl = #ddl + char(13) +
',[' + cast(#minyear as varchar(4)) + '_' + case when #i = 0 then 'En' else 'Disen' end + 'rollment_Date] DATE NULL'
set #i = #i + 1
end
set #minyear = #minyear + 1
set #i = 0
end
set #ddl = #ddl + char(13) + ')'
exec (#ddl)
If you set a value to #maxyear (for example in the declaration, with declare #maxyear int = 2023) you can check the columns reach the year 2023.
You can test on this db<>fiddle

MSSQL - How to not allow multiple users to view same set of records

e.g.
in table I have following records
a
b
c
d
e
f
g
h
I want to retrieved records by page
say 4 records per page
user x picks
a
b
c
d
Now user y should not pick any of the above
e
f
g
h
user x processes a record say record b
now he should see
a
e
c
d
and user y should see
f
g
h
i
how can I accomplish this, is there any built in way in mssql?
UPDATE
Here's what I have accomplished so far using auxilary table
http://sqlfiddle.com/#!18/e96f1/1
AllocateRecords2 2, 5, 1
GO
AllocateRecords2 2, 5, 2
both the queries are returning same set of results
I think you can use an auxiliary table UserData
CREATE TABLE Data(
ID int NOT NULL IDENTITY PRIMARY KEY,
Value varchar(1) NOT NULL
)
INSERT Data(Value)VALUES
('a'),
('b'),
('c'),
('d'),
('e'),
('f'),
('g'),
('h')
-- auxiliary table
CREATE TABLE UserData(
UserID int NOT NULL,
DataID int NOT NULL,
PRIMARY KEY(UserID,DataID),
FOREIGN KEY(DataID) REFERENCES Data(ID)
)
GO
And fill this table using the following procedure
CREATE PROC AddDataToUserData
#UserID int
AS
INSERT UserData(DataID,UserID)
SELECT TOP 4 ID,#UserID
FROM Data d
WHERE ID NOT IN(SELECT DataID FROM UserData)
ORDER BY ID
GO
Execute procedure for each other users
--TRUNCATE TABLE UserData
EXEC AddDataToUserData 1
EXEC AddDataToUserData 2
EXEC AddDataToUserData 3
...
Select data for a specific user
SELECT d.*
FROM Data d
JOIN UserData u ON u.DataID=d.ID
WHERE u.UserID=1
SELECT d.*
FROM Data d
JOIN UserData u ON u.DataID=d.ID
WHERE u.UserID=2
You can also create procedure for it
CREATE PROC GetDataForUser
#UserID int
AS
SELECT d.*
FROM Data d
JOIN UserData u ON u.DataID=d.ID
WHERE u.UserID=#UserID
GO
And then use it
EXEC GetDataForUser 1
EXEC GetDataForUser 2
Hope I understood your question correctly. But if I'm wrong you may use it as an idea.
I've added one column PageNumber into AllocatedRecords
/*
DROP TABLE Alphabets
DROP TABLE AllocatedRecords
GO
*/
CREATE TABLE Alphabets
(
ID INT IDENTITY(1,1) PRIMARY KEY,
Record varchar(1)
)
GO
CREATE TABLE [dbo].[AllocatedRecords](
[ID] [bigint] IDENTITY(1,1) NOT NULL primary key,
[ReferenceID] [int] NULL,
[IsProcessed] [bit] NULL,
[AllocatedToUser] [int] NULL,
[AllocatedDate] [datetime] NULL,
[ProcessedDate] [datetime] NULL,
PageNumber int -- new column
)
GO
INSERT Alphabets VALUES('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')
GO
And changed your procedure
DROP PROC AllocateRecords2
GO
CREATE PROC AllocateRecords2
(
#UserID INT,
#PageSize INT,
#PageNumber INT
)
AS
BEGIN
DECLARE #Today DATETIME
SET #Today = GETDATE()
--deallocated expired items
--TRUNCATE TABLE AllocatedRecords
DELETE AllocatedRecords
WHERE IsProcessed = 0 AND
(
(DATEDIFF(minute, #Today, AllocatedDate) > 5)
OR (AllocatedToUser = #UserID AND PageNumber <> #PageNumber)
)
DECLARE
#Draw INT = 10,
#PoolSize INT = #PageSize,
#CurrentRecords INT = (SELECT Count(*) from AllocatedRecords WHERE AllocatedToUser = #UserID AND IsProcessed = 0)
IF #CurrentRecords = 0
BEGIN
SET #Draw = #PoolSize
END
ELSE IF #CurrentRecords < #PoolSize
BEGIN
SET #Draw = #PoolSize - #CurrentRecords
END
ELSE IF #CurrentRecords >= #PoolSize
BEGIN
SET #Draw = 0
END
IF #Draw>0
BEGIN
INSERT AllocatedRecords(ReferenceID,IsProcessed,AllocatedToUser,AllocatedDate,ProcessedDate,PageNumber)
SELECT ID, 0, #UserID, GETDATE(), NULL, #PageNumber
FROM Alphabets
WHERE ID NOT IN (SELECT ReferenceID FROM AllocatedRecords)
ORDER BY ID
OFFSET (#PageNumber - 1) * #PageSize ROWS
FETCH NEXT #Draw ROWS ONLY
END
SELECT x.ID, x.Record
FROM AllocatedRecords A
JOIN Alphabets x ON A.ReferenceID = x.ID
WHERE AllocatedToUser = #UserID
AND IsProcessed = 0
SELECT COUNT(*) as TotalRecords
FROM AllocatedRecords
WHERE AllocatedToUser = #UserID
AND IsProcessed = 0
END
GO
Test
TRUNCATE TABLE AllocatedRecords
GO
-- user 2
EXEC AllocateRecords2 2, 5, 1
EXEC AllocateRecords2 2, 5, 2
EXEC AllocateRecords2 2, 5, 2 -- the same page
EXEC AllocateRecords2 1, 5, 1 -- user 1
EXEC AllocateRecords2 3, 5, 1 -- user 3

How to write this procedure to get auto-increment alphanumeric id in SQL Server?

Table structure is as follows:
CREATE TABLE tblContact
(
SrNo DECIMAL IDENTITY(1,1) NOT NULL,
InquiryId VARCHAR(10) PRIMARY KEY,
SenderName VARCHAR(50),
SenderEmail VARCHAR(200),
SenderSubject VARCHAR(50),
SenderMessage VARCHAR(MAX),
IsActive BIT DEFAULT(1),
IsDelete BIT DEFAULT(0),
CreatedOn DATETIME DEFAULT(GETDATE()),
CreatedBy VARCHAR(10),
UpdatedOn DATETIME,
UpdatedBy VARCHAR(10)
)
Procedure listing is as follows:
CREATE PROC Usp_GetNewInquiryId
AS
BEGIN
IF NOT EXISTS(SELECT InquiryId FROM JobPortal.dbo.tblContact)
DECLARE #PrefixValue VARCHAR(10) = 'INQ'
DECLARE #InitialValue DECIMAL(10) = 1001
SELECT InquiryId = #PrefixValue + CAST(ISNULL(MAX(InquiryId), #InitialValue) AS VARCHAR(10))
FROM JobPortal.dbo.tblContact
ELSE
/* here I want to eliminate the word 'INQ' from 'INQ1001' towards left side and do increment 1002 from 1001, lastly want to select INQ1002 and so on... */
SELECT TOP 1
InquiryId = #PrefixValue + CONVERT(VARCHAR(10), SUBSTRING(InquiryId, 4, 4)) + 1
FROM JobPortal.dbo.tblContact
ORDER BY InquiryId DESC
END
Desired Output:
If table is empty then InquiryId=INQ1001
Otherwise InquiryId=INQ1002
If you want to return the "next available" InquiryId for tblContact, I would do this:
CREATE PROCEDURE Usp_GetNewInquiryId
AS
BEGIN
IF NOT EXISTS (SELECT InquiryId FROM tblContact)
SELECT 'INQ1001'
ELSE
SELECT TOP 1 'INQ' + CONVERT(VARCHAR,CONVERT(INT,REPLACE(InquiryId,'INQ','')) + 1) FROM tblContact ORDER BY InquiryId DESC
END

Can I create a trigger on insert that will generate a random number for a key in SQL Server 2012?

I have the following table definition:
CREATE TABLE Content (
[ContentId] INT IDENTITY (1, 1) NOT NULL,
[Title] NVARCHAR (50) Not NULL,
CONSTRAINT [PK_Content] PRIMARY KEY CLUSTERED ([ContentId] ASC)
)";
Instead of an identity column I need to generate a random 5 digit number for the ContentId and for this number to have not been previously used.
Is there a way I can do this with some kind of database trigger for an insert in SQL Server 2012 ?
You are only dealing with 100,000 values. My suggestion is to create a lookup table for mapping an auto-incremented id to a new id. Here is the code for creating such a table:
with nums as (
select 0 as n
union all
select n + 1
from nums
where n < 9
),
nums5 as (
select n1.n*10000+n2.n*1000+n3.n*100+n4.n+10+n5.n as val
from nums n1 cross join nums n2 cross join nums n3 cross join
nums n4 cross join nums n5
)
select val,
row_number() over (order by newid()) as new_content_id
into LookupTable
from nums5;
With this table, put an auto-incremented id in the table and then lookup the five character "new_content_id" from this table.
This can be a good starting point to do what you want :
SQL Fiddle
MS SQL Server 2012 Schema Setup:
CREATE TABLE Content (
[ContentId] INT NOT NULL,
[Title] NVARCHAR (50) Not NULL,
CONSTRAINT [PK_Content] PRIMARY KEY CLUSTERED ([ContentId] ASC)
);
Query 1:
DECLARE #key VARCHAR(5), #i int
DECLARE #query VARCHAR(120)
SET #i = 1
WHILE #i > 0
BEGIN
SET #key = (SELECT ABS(Checksum(NewID()) % 89999) + 10000)
SET #i = (SELECT count(*) FROM Content WHERE ContentId = #key)
END
SET #query = 'INSERT INTO Content (ContentId,Title) VALUES ('+#key+',''Whatever'+#key+''');'
exec(#query)
Results:
Query 2:
DECLARE #key VARCHAR(5), #i int
DECLARE #query VARCHAR(120)
SET #i = 1
WHILE #i > 0
BEGIN
SET #key = (SELECT ABS(Checksum(NewID()) % 89999) + 10000)
SET #i = (SELECT count(*) FROM Content WHERE ContentId = #key)
END
SET #query = 'INSERT INTO Content (ContentId,Title) VALUES ('+#key+',''Whatever'+#key+''');'
exec(#query)
Results:
Query 3:
select * from Content
Results:
| CONTENTID | TITLE |
|-----------|---------------|
| 22537 | Whatever22537 |
| 66089 | Whatever66089 |

getdate() performance issue sql server 2000

I have a table with fallowing columns
symbol |market| bid_price | ask_price | update_time
------- ------ ----------- ----------- ------------
ABC US 123.00 675.00 20012-09-10 4:24:32.986
CDE SG 456.00 545.00 20012-09-10 4:26:32.986
And my application calling a SP for update this table.
update price_tbl
set bid_price=#bid_price, ask_price=#ask_price, update_time = getdate()
where market = #market and symbol = #symbol
But my application calling more than 1000 updates per second. so this SP not fast enough to update the table. I checked and found getdate() function is the bottleneck. but this system running with sql server 2000.
Can I use any other method to update time other than getdate() Any
other proposal for increase performance of this update.
FYI: this price_tbl having around 2000 records.
Eddied with test result.
Table Definition
..........................................................................................
CREATE TABLE [dbo].[GLDPrice](
[Company_code] [varchar](10) NOT NULL,
[Symbol] [varchar](10) NOT NULL,
[SymbolA] [varchar](10) NULL,
[SymbolB] [varchar](10) NULL,
[Market] [char](2) NOT NULL,
[ExchangeCode] [varchar](4) NULL,
[Remark] [char](6) NULL,
[Last_done] [numeric](19, 8) NULL,
[Change] [numeric](19, 8) NOT NULL,
[Open_Price] [numeric](19, 8) NULL,
[Closing_Price] [numeric](19, 8) NULL,
[Buy_Price] [numeric](19, 8) NULL,
[Sell_Price] [numeric](19, 8) NULL,
[Day_High] [numeric](19, 8) NULL,
[Day_Low] [numeric](19, 8) NULL,
[Time_done] [char](5) NULL,
[Cumm_vol] [int] NOT NULL,
[Buy_quantity] [int] NULL,
[Sell_quantity] [int] NULL,
[Per_Change] [numeric](19, 8) NULL,
[GLDBid] [numeric](19, 8) NULL,
[GLDAsk] [numeric](19, 8) NULL,
[GlobalGLDBid] [numeric](19, 8) NULL,
[GlobalGLDAsk] [numeric](19, 8) NULL,
[GLDBuyLastDone] [numeric](19, 8) NULL,
[GLDSellLastDone] [numeric](19, 8) NULL,
[GLDBuyLDUptTime] [datetime] NULL,
[GLDSellLDUptTime] [datetime] NULL,
[UpdateTime] [datetime] NOT NULL,
CONSTRAINT [PK_GLDPrice] PRIMARY KEY CLUSTERED
(
[Company_code] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[GLDPrice] ADD CONSTRAINT [DF_GLDPrice_SymbolA] DEFAULT (' ') FOR [SymbolA]
GO
ALTER TABLE [dbo].[GLDPrice] ADD CONSTRAINT [DF_GLDPrice_Last_done] DEFAULT (0) FOR [Last_done]
GO
ALTER TABLE [dbo].[GLDPrice] ADD DEFAULT (getdate()) FOR [UpdateTime]
GO
SP with getdate()
..........................................................................................
ALTER PROCEDURE [dbo].[update_test_one]
#Symbol varchar(10),
#Market varchar(5),
#BuyPrice money,
#SellPrice money,
#LastPrice money,
#High money,
#Low money
AS
DECLARE #GLDBidPrice money
DECLARE #GLDAskPrice money
DECLARE #GlobalGLDBid money
DECLARE #GlobalGLDAsk money
DECLARE #GLDBidAdjust money
DECLARE #GLDAskAdjust money
DECLARE #GlobalBidAdjust money
DECLARE #GlobalAskAdjust money
SELECT #GLDBidPrice = #BuyPrice + 5
SELECT #GLDAskPrice = #SellPrice + 5
SELECT #GlobalGLDBid = #BuyPrice + 5
SELECT #GlobalGLDAsk = #SellPrice + 5
UPDATE dbo.GLDprice
SET Buy_price = #BuyPrice,
Sell_price = #SellPrice,
GLDBid = #GLDBidPrice,
GLDAsk = #GLDAskPrice,
Day_high = #High,
Day_Low = #Low,
GlobalGLDBid = #GlobalGLDBid,
GlobalGLDAsk = #GlobalGLDAsk,
UpdateTime=GetDate(),
Last_Done = #LastPrice
WHERE Symbol = #symbol AND Market = #Market
SP without getdata()
............................................................................................
ALTER PROCEDURE [dbo].[update_test_two]
#Symbol varchar(10),
#Market varchar(5),
#BuyPrice money,
#SellPrice money,
#LastPrice money,
#High money,
#Low money
AS
DECLARE #GLDBidPrice money
DECLARE #GLDAskPrice money
DECLARE #GlobalGLDBid money
DECLARE #GlobalGLDAsk money
DECLARE #GLDBidAdjust money
DECLARE #GLDAskAdjust money
DECLARE #GlobalBidAdjust money
DECLARE #GlobalAskAdjust money
SELECT #GLDBidPrice = #BuyPrice + 5
SELECT #GLDAskPrice = #SellPrice + 5
SELECT #GlobalGLDBid = #BuyPrice + 5
SELECT #GlobalGLDAsk = #SellPrice + 5
UPDATE dbo.GLDprice
SET Buy_price = #BuyPrice,
Sell_price = #SellPrice,
GLDBid = #GLDBidPrice,
GLDAsk = #GLDAskPrice,
Day_high = #High,
Day_Low = #Low,
GlobalGLDBid = #GlobalGLDBid,
GlobalGLDAsk = #GlobalGLDAsk,
Last_Done = #LastPrice
WHERE Symbol = #symbol AND Market = #Market
Test Script
...........................................................................................
DECLARE #return_value int
DECLARE #count int
DECLARE #start datetime
SET NOCOUNT ON
SET #count = 0;
set #start = CURRENT_TIMESTAMP
WHILE (#count < 10000)
BEGIN
SET #count = #count + 1
EXEC [dbo].[update_test_one]
#Symbol = N'I9T',
#Market = N'SG',
#BuyPrice = 0.8,
#SellPrice = 0.8,
#LastPrice = 0.8,
#High = 0.8,
#Low = 0.8
EXEC [dbo].[update_test_one]
#Symbol = N'0001.HK',
#Market = N'HK',
#BuyPrice = 112,
#SellPrice = 112,
#LastPrice = 112,
#High = 112,
#Low = 112
END
print 'Test 01 : ' + CONVERT(varchar(20),DATEDIFF(millisecond,#start,CURRENT_TIMESTAMP))
SET #count = 0;
set #start = CURRENT_TIMESTAMP
WHILE (#count < 10000)
BEGIN
SET #count = #count + 1
EXEC [dbo].[update_test_two]
#Symbol = N'I9T',
#Market = N'SG',
#BuyPrice = 0.8,
#SellPrice = 0.8,
#LastPrice = 0.8,
#High = 0.8,
#Low = 0.8
EXEC [dbo].[update_test_two]
#Symbol = N'0001.HK',
#Market = N'HK',
#BuyPrice = 112,
#SellPrice = 112,
#LastPrice = 112,
#High = 112,
#Low = 112
END
print 'Test 02 : ' + CONVERT(varchar(20),DATEDIFF(millisecond,#start,CURRENT_TIMESTAMP))
GO
Result:
Test 01 : 82310
Test 02 : 12176
Result with reverse test.
Test 02 : 15413
Test 01 : 81636
I checked and found getdate() function is the bottleneck
I can absolutely 100% guarantee that your finding is wrong. The performance problem is by no means getdate(). For the record, not only calling getdate() 1000 times is not visible in the performance, but getdate()` happens to be a runtime constant function!
If you want to troubleshoot SQL Server performance issues, follow a methodology like Waits and Queues or follow the Performance Troubleshooting Flowchart.
My bet is that the performance problem is here:
where market = #market and symbol = #symbol
You're either missing an appropriate index on (market, symbol) or the type of the parameters #market and/or #symbol are incorrect and, due to data type precedence rules, cause table scans instead of index seeks.
Since you haven't presented a benchmark, I thought I'd do one, and then everyone can poke holes in the methodology. Hence CW :-):
SET NOCOUNT ON
go
create table prices (symbol char(3) not null,market char(2) not null,
bid_price decimal(18,4) not null,ask_price decimal(18,4) not null,
update_time datetime not null,
constraint PK_prices PRIMARY KEY (symbol,market)
)
GO
create table #Digits (d int not null)
insert into #Digits (d)
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
create table #Numbers (n int not null)
insert into #Numbers (n)
select d1.d * 10000 + d2.d * 1000 + d3.d * 100 + d4.d * 10 + d5.d
from #Digits d1,#Digits d2,#Digits d3,#Digits d4,#Digits d5
insert into prices (symbol,market,bid_price,ask_price,update_time)
select
CHAR(65+n/(26*26)) + CHAR(65+((n/26)%26)) + CHAR(65+(n%26)),m.market,n,n+5,GETDATE()
from
#Numbers nu,
(select 'US' as market union all select 'SG') m
where nu.n < (26*26*26)
go
drop table #Digits
drop table #Numbers
The above sets us up with a table with ~30000 rows (so, more than you say you have). It also warms up the table, because every row has been recently accessed. I can't remember what invocations will clear this out for SQL Server 2000, but it ought to be fair enough to now run the tests in either order.
declare #market char(2)
declare #symbol char(3)
declare #price1 decimal(18,4)
declare #price2 decimal(18,4)
declare #start datetime
declare updates cursor local static for select symbol,market,bid_price,ask_price from prices
open updates
set #start = CURRENT_TIMESTAMP
fetch next from updates into #symbol,#market,#price1,#price2
while ##FETCH_STATUS = 0
begin
update prices
set bid_price=#price2, ask_price=#price1
where market = #market and symbol = #symbol
fetch next from updates into #symbol,#market,#price1,#price2
end
close updates
deallocate updates
print '"FAST" took ' + CONVERT(varchar(20),DATEDIFF(millisecond,#start,CURRENT_TIMESTAMP))
go
declare #market char(2)
declare #symbol char(3)
declare #price1 decimal(18,4)
declare #price2 decimal(18,4)
declare #start datetime
declare updates cursor local static for select symbol,market,bid_price,ask_price from prices
open updates
set #start = CURRENT_TIMESTAMP
fetch next from updates into #symbol,#market,#price1,#price2
while ##FETCH_STATUS = 0
begin
update prices
set bid_price=#price2, ask_price=#price1,update_time = GETDATE()
where market = #market and symbol = #symbol
fetch next from updates into #symbol,#market,#price1,#price2
end
close updates
deallocate updates
print '"SLOW" took ' + CONVERT(varchar(20),DATEDIFF(millisecond,#start,CURRENT_TIMESTAMP))
go
drop table prices
The only difference between these two cursor loops is that the second one does the GETDATE() based update to update_time, whereas the first performs no update to this column (as you indicated you'd done in your testing).
On my machine(*) , I get the result:
"FAST" took 20503
"SLOW" took 20436
Which indicates that the "slow" method, using GETDATE(), was 0.1 seconds faster.
(*)
Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
May 3 2005 23:18:38
Copyright (c) 1988-2003 Microsoft Corporation
Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
DECLARE #CurrentDate DateTime;
SELECT #CurrentDate = getdate();
update price_tbl
set bid_price=#bid_price, ask_price=#ask_price, update_time = #CurrentDate
where market = #market and symbol = #symbol
See if this works
I had a scenario like this and i gave a solution like this,
I passed the date time as the parameter from the front end to SP. otherwise if you want to handle in the SP itself you can go for this, like
DECLARE #time DATETIME
Set #time = getdate()
and you can pass it to your argument list, but note that we wont get the exact milliseconds in some case we handle that too in front end. because all record will have same present time with only different second value.
In front end yo can pass the value as,
DateTime.Now.ToString("HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo)
DateTime.Now.ToString("HH:mm:ss.fff", System.Globalization.DateTimeFormatInfo.InvariantInfo)
This works for me Test 01 : 266
ALTER PROCEDURE [dbo].[update_test_one]
#Symbol varchar(10),
#Market varchar(5),
#BuyPrice money,
#SellPrice money,
#LastPrice money,
#High money,
#Low money
AS
SET NOCOUNT ON;
UPDATE P
SET P.Buy_price = #BuyPrice,
P.Sell_price = #SellPrice,
P.GLDBid = #BuyPrice + C.BidRate,
P.GLDAsk = #SellPrice + isnull(C.AskRate,0),
P.Day_high = #High,
P.Day_Low = #Low,
P.GlobalGLDBid = #BuyPrice+ isnull(C.BidRateGlobal,0),
P.GlobalGLDAsk = #SellPrice+isnull(C.AskRateGlobal,0),
P.UpdateTime=CONVERT(VARCHAR(20), GETDATE(), 120),
P.Last_Done = #LastPrice
FROM dbo.GLDPrice AS P
INNER JOIN DBO.GLDContract AS C
ON P.Company_code=C.Company_code
WHERE P.Symbol = #symbol AND P.Market = #Market
SET NOCOUNT OFF

Resources