How to convert a bigint to float - sql-server

I know that a bigint should implicitly convert to a float but it does not seem to.
Table column to be updated:
[GBUsed] [float] NOT NULL,
Example of data in that column:
430.5
Logic: I'm summing 2 bigint columns together and dividing by 1024. An example of 1 of the row - I get: 1545
I the update the GBUsed column which is defined as float but it does not convert. I still get the 1545.
Stored procedure:
CREATE PROCEDURE [dbo].[RecalculateBandwidthUsage]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #RowCount int,
#Rc int,
#Message varchar(max),
#CurrentDateTime datetime
CREATE TABLE #Temp
(
SwitchID int,
PortIndex int,
SwitchIP varchar(50),
GBUsed bigint
)
SET #CurrentDateTime = GETDATE()
-- FOR TESTING:
BEGIN TRANSACTION
INSERT #Temp (SwitchID, PortIndex, SwitchIP, GBUsed)
SELECT
c.SwitchID, c.PortIndex,
s.SwitchIP,
SUM ((c.BandwidthIn + c.BandwidthOut) / 1024) AS GBUsed -- converting to gigabytes
FROM
dbo.BandwidthLogCalculatedTest6 c
INNER JOIN
Switch s ON (c.SwitchID = s.SwitchID)
WHERE
(c.StartDate < DATEADD(HOUR, -1, #CurrentDateTime)
AND c.EntryType = 'Second')
GROUP BY
c.SwitchID, c.PortIndex, s.SwitchIP
ORDER BY
c.PortIndex
SELECT
#Rc = ##ERROR,
#RowCount = ##ROWCOUNT
IF #Rc <> 0
BEGIN
SELECT #Message = 'Critical Error - procedure RecalculateBandwidthUsage - on select. Return code: ' + Cast(#Rc as varchar)
RAISERROR (#Message, 16, 1)
END
-- FOR TESTING:
SELECT 'Temp table '
SELECT *
FROM #temp
ORDER BY PortIndex
IF #RowCount > 0
BEGIN
-- FOR TESTING:
SELECT 'Before update '
SELECT b.SwitchIP, b.SwitchPort, b.GBUsed
FROM dbo.Bandwidth b
INNER JOIN #temp t ON (b.SwitchIP = t.SwitchIP AND b.SwitchPort = t.PortIndex )
ORDER BY b.SwitchPort
-- Update.
UPDATE dbo.Bandwidth
SET GBUsed = CONVERT(float, t.Gbused)
FROM #Temp t
WHERE (Bandwidth.SwitchIP = t.SwitchIP AND Bandwidth.SwitchPort = t.PortIndex)
SELECT #Rc = ##ERROR
IF #Rc <> 0
BEGIN
SELECT #Message = 'Critical Error - procedure RecalculateBandwidthUsage - on Bandwidth update. Return code: ' + Cast(#Rc as varchar)
RAISERROR (#Message, 16, 1)
END
-- FOR TESTING:
SELECT 'After update '
SELECT b.SwitchIP, b.SwitchPort, b.GBUsed
FROM dbo.Bandwidth b
INNER JOIN #temp t ON (b.SwitchIP = t.SwitchIP AND b.SwitchPort = t.PortIndex)
ORDER BY b.SwitchPort
END
ROLLBACK TRANSACTION
END

You are doing an integer division - so therefore, your result will also be an integer (or BIGINT).
You need to use this code in order to get fractional values:
SUM ((c.BandwidthIn + c.BandwidthOut) / 1024.0) AS GBUsed
Dividing by 1024.0 (instead of just 1024) will make sure to use fractional values

Related

Getting error when executing the stored procedure using SQL Server

I get an error
Subquery returned more than 1 value
when executing a stored procedure. I need to copy data from the database I am building to the live database. The code inserted the data into TestTextmessage table and updateed TextMessage table. The error occurred when try to insert into the TestMobileRecipient table that is the reason why the table is empty.
The table structure and code are below
Stored procedure
CREATE PROCEDURE [dbo].[TestSendITMessage]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #i int
DECLARE #idmessage int
DECLARE #numrows int
DECLARE #messagehold TABLE
(
idx SMALLINT PRIMARY KEY IDENTITY(1,1),
MessageId INT
)
DECLARE #InsertedID INT
INSERT INTO #messagehold
SELECT DISTINCT Id
FROM [MPFT_SendIT].dbo.TextMessage
WHERE DontSendBefore < GETDATE()
AND DateSent IS NULL
AND MessageSent = 0
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #messagehold)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #messagehold))
BEGIN
SET #idmessage = (SELECT MessageId FROM #messagehold WHERE idx = #i)
--Do something with Id here
PRINT #idmessage
INSERT INTO [dbo].[TestTextMessage] ([Origin], [MessageBody], [MessageSent], [DateCreated], DontSendBefore)
SELECT
'LogIT', MessageBody, 0, GETDATE(), DontSendBefore
FROM
[MPFT_SendIT].dbo.TextMessage
WHERE Id = #idmessage
SET #InsertedID = SCOPE_IDENTITY();
INSERT INTO [dbo].[TestMobileRecipient] ([MessageId], MobileNumber])
VALUES (#InsertedID, (SELECT MobileNumber FROM MobileRecipient
WHERE MessageId = #idmessage))
UPDATE TextMessage
SET DateSent = GETDATE(),
MessageSent = 1
WHERE Id = #idmessage
SET #i = #i + 1
END
END
the error message is very clear. Your sub-query SELECT MobileNumber FROM MobileRecipient WHERE MessageId= #idmessage is returning more than 1 row
Change the insertion of table TestMobileRecipient to following
Insert into [dbo].[TestMobileRecipient]
(
[MessageId]
,[MobileNumber]
)
SELECT #InsertedID
, MobileNumber
FROM MobileRecipient
WHERE MessageId= #idmessage
You should update your this line
SET #idmessage = (SELECT MessageId FROM #messagehold WHERE idx = #i)
with
SET #idmessage = (SELECT top 1 MessageId FROM #messagehold WHERE idx = #i)

Trigger did not run?

I have a trigger "after insert/update/delete/". It is supposed to count Balance on Account table based on transactions in Transaction table. It is on Transaction table. I am getting Balance discrepancies rarely, so have decided to add some logging into it. It dumps inserted+deleted tables (they are combined into a table var) and tsql statement which fired it. Judging from my log, it looks like the trigger did not fire for some inserts into Transaction table. Can this happen ? Are there any TSQL statement which change table data without firing trigger (except truncate table etc)?
Here is the trigger :
CREATE TRIGGER [dbo].[trg_AccountBalance]
ON [dbo].[tbl_GLTransaction]
AFTER INSERT, UPDATE, DELETE
AS
set nocount on
begin try
declare #OldOptions int = ##OPTIONS
set xact_abort off
declare #IsDebug bit = 1
declare #CurrentDateTime datetime = getutcdate()
declare #TriggerMessage varchar(max), #TriggerId int
if #IsDebug = 1
begin
select #TriggerId = isnull(max(TriggerId), 0) + 1
from uManageDBLogs.dbo.tbl_TriggerLog
declare #dbcc_INPUTBUFFER table(EventType nvarchar(30), Parameters Int, EventInfo nvarchar(4000) )
declare #my_spid varchar(20) = CAST(##SPID as varchar(20))
insert #dbcc_INPUTBUFFER
exec('DBCC INPUTBUFFER ('+#my_spid+')')
select #TriggerMessage = replace(EventInfo, '''', '''''') from #dbcc_INPUTBUFFER
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
declare #Oper int
select #Oper = 0
-- determine type of sql statement
if exists (select * from inserted) select #Oper = #Oper + 1
if exists (select * from deleted) select #Oper = #Oper + 2
if #IsDebug = 1
begin
select #TriggerMessage = '#Oper = ' + convert(varchar, #Oper)
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
if #Oper = 0 return -- No data changed
declare #TomorrowDate date = dateadd(day, 1, convert(date, getdate()))
declare #CurrentDate date = convert(date, getdate())
-- transactions from both inserted and deleted tables
declare #tbl_Trans table (FirmId int, GLAccountId int,
AmountDebit money, AmountCredit money, "Status" char(1), TableType char(1))
declare #tbl_AccountCounters table (FirmId int, GLAccountId int, Balance money)
declare #IsChange bit = null
insert into #tbl_Trans (FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", TableType)
select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'I'
from inserted
union
select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'D'
from deleted
if #IsDebug = 1
begin
select #TriggerMessage = (select * from #tbl_Trans for xml path ('tbl_Trans'))
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
insert into #tbl_AccountCounters (FirmId, GLAccountId, Balance)
select FirmId, GLAccountId, 0
from #tbl_Trans
group by FirmId, GLAccountId
if #Oper = 1 or #Oper = 2 -- insert/delete
begin
update #tbl_AccountCounters
set Balance = cnt.TransSum
from #tbl_AccountCounters as ac join
(
select trans.FirmId, trans.GLAccountId,
isnull(sum((trans.AmountDebit - trans.AmountCredit) * iif(trans.TableType = 'I', 1, -1)), 0) as TransSum
from #tbl_Trans as trans
where trans.Status = 'A'
group by trans.FirmId, trans.GLAccountId
) as cnt on ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId
select #IsChange = 1
end
else
begin
if update(AmountDebit) or update(AmountCredit) or update(Status) or update(GLAccountId)
begin
update #tbl_AccountCounters
set Balance = cnt.TransBalance
from #tbl_AccountCounters as ac join
(select trans.FirmId, trans.GLAccountId, isnull(sum(trans.AmountDebit - trans.AmountCredit), 0) as TransBalance
from dbo.tbl_GLTransaction as trans
where trans."Status" = 'A' and exists (select 1 from #tbl_AccountCounters as ac
where ac.GLAccountId = trans.GLAccountId and ac.FirmId = trans.FirmId)
group by trans.FirmId, trans.GLAccountId) as cnt on
ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId
select #IsChange = 0
end
end
if #IsDebug = 1
begin
select #TriggerMessage = '#IsChange = ' + isnull(convert(varchar, #IsChange), 'null')
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
select #TriggerMessage = (select * from #tbl_AccountCounters for xml path ('tbl_AccountCounters'))
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
if #IsChange is not null
begin
update tbl_GLAccount
set tbl_GLAccount.Balance = iif(#IsChange = 1, cnt.Balance + acc.Balance, cnt.Balance),
tbl_GLAccount.LastUpdate = getutcdate(),
tbl_GLAccount.LastUpdatedBy = 1
from #tbl_AccountCounters as cnt join dbo.tbl_GLAccount as acc on
cnt.FirmId = acc.FirmId and cnt.GLAccountId = acc.GLAccountId
end
if (16384 & #OldOptions) = 16384 set xact_abort on
end try
begin catch
declare #ErrorLine varchar(max)
select #ErrorLine = uManageDb.dbo.udf_GetErrorInfo()
insert into uManageDb.dbo.tbl_TriggerError ("Name", "Message", CreateDate)
values ('AccountingDB..trg_AccountBalance', #ErrorLine, GETUTCDATE())
end catch
I think I've found it. I have this line:
select .. from inserted
union
select .. from deleted
and they inserted 5 trans for $300 and 4 trans $100. I've got 2 records (300 and 100) in my #tbl_Trans (it was in the log). That's probably was the bug. So log hellps and trigger run as it had to.
I'll replace union with union all.

Calculating distance between 2 zips by using a function

I have a table of which first 3 rows look like:
ship_to_zip Knoxville_Zip Phoenix_Zip
52773 37909 85009
46341 37909 85009
83114 37909 85009
I have a function that calculates distance in miles between 2 zips: dbo.ufnzipcodedist_2012(zip1,zip2)
Now I want to add 2 more columns to my table: Miles_from_Knoxville and Miles_from_Phoenix, each which calculates miles between ship_to_id and Knoxville_Zip/Phoenix_Zip respectively.
I tried below:
select IDENTITY(Int,1,1) ID,*,CAST(0 as float) dist1,CAST(0 as FLOAT) DIST2
INTO #TEMP
from #zip
declare #COUNT INT
DECLARE #DIST1 FLOAT
DECLARE #DIST2 FLOAT
set #COUNT=1
while (#COUNT<=2)
begin
SELECT #DIST1=dbo.ufnzipcodedist_2012(SHIP_TO_ZIP,KNOXVILLE_ZIP)
,#DIST2=dbo.ufnzipcodedist_2012(SHIP_TO_ZIP,PHOENIX_ZIP)
FROM #TEMP
UPDATE t SET T.DIST1=#DIST1,t.DIST2=#DIST2
FROM #TEMP t
WHERE ID=#COUNT
set #COUNT=#COUNT+1
end
It is going into a infinite loop and columns DIST1, DIST2 are populated with 0s. Where did I go wrong?
Please Modify your query as below:
SELECT IDENTITY(INT, 1, 1) ID
,*
,CAST(0 AS FLOAT) dist1
,CAST(0 AS FLOAT) DIST2
INTO #TEMP
FROM #zip
DECLARE #COUNT INT
,#DIST1 FLOAT
,#DIST2 FLOAT
,#MAXID INT
SET #COUNT = 1
SELECT #MAXID = MAX(ID)
FROM #TEMP
WHILE (#COUNT <= #MAXID)
BEGIN
SELECT #DIST1 = dbo.ufnzipcodedist_2012(z1, z2)
,#DIST2 = dbo.ufnzipcodedist_2012(z2, z3)
FROM #TEMP
WHERE ID = #COUNT
UPDATE t
SET T.DIST1 = #DIST1
,t.DIST2 = #DIST2
FROM #TEMP t
WHERE ID = #COUNT
SET #COUNT = #COUNT + 1
END
SELECT *
FROM #TEMP
Here is a link to SQL fiddle:http://sqlfiddle.com/#!6/b5699/3

Insert statement with random generated number

What I'm trying to accomplish is to assign a 5 digit number to a row in the table and insert that value with column value to a different table.
For example, this query returns all the rows that I would like to assign a 5 digit random ID:
SELECT DISTINCT(ExternalAgentId) FROM lOGS_V WHERE EXTERNALAGENTID <> ''
Currently it's returning 4600 rows. NOTE* ExternalAgentID is varchar(50)
What I need to do is assign a random 5 digit number between 10001 and 39999. Once I generate the number insert it to the table with ExternalAgentId from previous query to another table.
Here's the approach I took:
DECLARE #randAgentID int;
DECLARE #AgentID int;
DECLARE #MIN INT;
DECLARE #MAX INT;
SET #MIN = 10001
SET #MAX = 39999
SELECT #randAgentID = ROUND(((#MAX - #MIN -1) * RAND() + #MIN), 0)
SELECT #AgentID = InternalAgentID FROM VendorAgentIDs where InternalAgentID = #randAgentID
IF #AgentID is null
BEGIN
INSERT INTO VendorAgentIDs (VendorID, TRIAgentID) values (SELECT DISTINCT(ExternalAgentId) FROM LOGS_V WHERE EXTERNALAGENTID <> '', #randAgentID)
END
ELSE
BEGIN
SELECT #randAgentID = ROUND(((#MAX - #MIN -1) * RAND() + #MIN), 0)
INSERT INTO VendorAgentIDs (VendorID, TRIAgentID) values (SELECT DISTINCT(ExternalAgentId) FROM LOGS_V WHERE EXTERNALAGENTID <> '', #randAgentID)
END
It's generating random 5 digit number correctly. However, I'm having two issues:
I have a syntax error in my insert statements.
...values (SELECT DISTINCT(ExternalAgentId)...
If the randAgentID exists in the table, it goes to the ELSE statement. I know the chances are low, but what if the next randAgentID also exists in the table? How can I prevent that?
The table VendorAgentIDs has three columns.
ID (autoincrement)
VendorID (varchar(50))
InternalAgentID (PK, int)
Any suggestions on how I can resolve the above two issues?
Thanks
* *UPDATE
Based on the suggestion, I edited my code. However, I now have a violation of PRIMARY KEY.
DECLARE #randAgentID int;
DECLARE #AgentID int;
DECLARE #MIN INT;
DECLARE #MAX INT;
SET #MIN = 10001
SET #MAX = 39999
SET #AgentID = 1
WHILE #AgentID IS NOT NULL
BEGIN
SET #AgentID = NULL
SELECT #randAgentID = ROUND(((#MAX - #MIN -1) * RAND() + #MIN), 0)
INSERT INTO VendorAgentIDs (VendorAgentID, InternalAgentID) SELECT DISTINCT(ExternalAgentId), #randAgentID FROM LOGS_V WHERE EXTERNALAGENTID <> ''
SELECT #AgentID = InternalAgentID FROM VendorAgentIDs where InternalAgentID = #randAgentID
END
Violation of PRIMARY KEY constraint 'PK_VendorAgentIDs'. Cannot insert duplicate key in object 'dbo.VendorAgentIDs'.
May be this will solve your PK issue
INSERT INTO VendorAgentIDs
(VendorAgentID,InternalAgentID)
SELECT DISTINCT ExternalAgentId,#randAgentID
FROM LOGS_V
WHERE EXTERNALAGENTID <> ''
AND ExternalAgentId NOT IN (SELECT VendorAgentID
FROM VendorAgentIDs)
INSERT INTO VendorAgentIDs (VendorID, TRIAgentID) values (SELECT DISTINCT(ExternalAgentId) FROM TRI_PORTAL.DBO.SCREENPOPLOGS_V WHERE EXTERNALAGENTID <> '', #randAgentID)
Is invalid SQL. However I think you can do
INSERT INTO VendorAgentIDs (VendorID, TRIAgentID) SELECT DISTINCT(ExternalAgentId), #randAgentID FROM TRI_PORTAL.DBO.SCREENPOPLOGS_V WHERE EXTERNALAGENTID <> ''
As for the possiblity (eventuality) of a collision you should just do a loop. It becomes increasingly inefficient but if it has to be a random number and not an index then, so be it.
SET #AgentID = 1
WHILE #AgentID is not null
BEGIN
SET #AgentID = NULL
SELECT #randAgentID = ROUND(((#MAX - #MIN -1) * RAND() + #MIN), 0)
SELECT #randAgentID -- why is this here?
SELECT #AgentID = InternalAgentID FROM VendorAgentIDs where InternalAgentID = #randAgentID
END

Using row count from a temporary table in a while loop SQL Server 2008

I'm trying to create a procedure in SQL Server 2008 that inserts data from a temp table into an already existing table. I think I've pretty much figured it out, I'm just having an issue with a loop. I need the row count from the temp table to determine when the loop should finish.
I've tried using ##ROWCOUNT in two different ways; using it by itself in the WHILE statement, and creating a variable to try and hold the value when the first loop has finished (see code below).
Neither of these methods have worked, and I'm now at a loss as to what to do. Is it possible to use ##ROWCOUNT in this situation, or is there another method that would work better?
CREATE PROCEDURE InsertData(#KeywordList varchar(max))
AS
BEGIN
--create temp table to hold words and weights
CREATE TABLE #tempKeywords(ID int NOT NULL, keyword varchar(10) NOT NULL);
DECLARE #K varchar(10), #Num int, #ID int
SET #KeywordList= LTRIM(RTRIM(#KeywordList))+ ','
SET #Num = CHARINDEX(',', #KeywordList, 1)
SET #ID = 0
--Parse varchar and split IDs by comma into temp table
IF REPLACE(#KeywordList, ',', '') <> ''
BEGIN
WHILE #Num > 0
BEGIN
SET #K= LTRIM(RTRIM(LEFT(#KeywordList, #Num - 1)))
SET #ID = #ID + 1
IF #K <> ''
BEGIN
INSERT INTO #tempKeywords VALUES (#ID, #K)
END
SET #KeywordList = RIGHT(#KeywordList, LEN(#KeywordList) - #Num)
SET #Num = CHARINDEX(',', #KeywordList, 1)
--rowcount of temp table
SET #rowcount = ##ROWCOUNT
END
END
--declaring variables for loop
DECLARE #count INT
DECLARE #t_name varchar(30)
DECLARE #key varchar(30)
DECLARE #key_weight DECIMAL(18,2)
--setting count to start from first keyword
SET #count = 2
--setting the topic name as the first row in temp table
SET #t_name = (Select keyword from #tempKeywords where ID = 1)
--loop to insert data from temp table into Keyword table
WHILE(#count < #rowcount)
BEGIN
SET #key = (SELECT keyword FROM #tempKeywords where ID = #count)
SET #key_weight = (SELECT keyword FROM #tempKeywords where ID = #count+2)
INSERT INTO Keyword(Topic_Name,Keyword,K_Weight)
VALUES(#t_name,#key,#key_weight)
SET #count= #count +2
END
--End stored procedure
END
To solve the second part of your problem:
INSERT INTO Keyword(Topic_Name,Keyword,K_Weight)
SELECT tk1.keyword, tk2.keyword, tk3.keyword
FROM
#tempKeywords tk1
cross join
#tempKeywords tk2
inner join
#tempKeywords tk3
on
tk2.ID = tk3.ID - 1
WHERE
tk1.ID = 1 AND
tk2.ID % 2 = 0
(This code should replace everything in your current script from the --declaring variables for loop comment onwards)
You could change:
WHILE(#count < #rowcount)
to
WHILE(#count < (select count(*) from #tempKeywords))
But like marc_s commented, you should be able to do this without a while loop.
I'd look at reworking your query to see if you can do this in a set based way rather than row by row.
I'm not sure I follow exactly what you are trying to achieve, but I'd be tempted to look at the ROW_NUMBER() function to set the ID of your temp table. Used with a recursive CTE such as shown in this answer you could get an id for each of your non empty trimmed words. An example is something like;
DECLARE #KeywordList varchar(max) = 'TEST,WORD, ,,,LIST, SOME , WITH, SPACES'
CREATE TABLE #tempKeywords(ID int NOT NULL, keyword varchar(10) NOT NULL)
;WITH kws (ord, DataItem, Data) AS(
SELECT CAST(1 AS INT), LEFT(#KeywordList, CHARINDEX(',',#KeywordList+',')-1) ,
STUFF(#KeywordList, 1, CHARINDEX(',',#KeywordList+','), '')
union all
select ord + 1, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from kws
where Data > ''
), trimKws(ord1, trimkw) AS (
SELECT ord, RTRIM(LTRIM(DataItem))
FROM kws
)
INSERT INTO #tempKeywords (ID, keyword)
SELECT ROW_NUMBER() OVER (ORDER BY ord1) as OrderedWithoutSpaces, trimkw
FROM trimKws WHERE trimkw <> ''
SELECT * FROM #tempKeywords
I don't fully understand what you are trying to acheive with the second part of your query , but but you could just build on this to get the remainder of it working. It certainly looks as though you could do what you are after without while statements at least.

Resources