I am trying to determine the size in bytes of the contents in a VARBINARY(MAX) field in SQL Server 2005, using SQL. As I doubt there is native support for this, could it be done using CLR integration? Any ideas would be greatly appreciated.
Actually, you can do this in T-SQL!
DATALENGTH(<fieldname>) will work on varbinary(max) fields.
The VARBINARY(MAX) field allocates variable length data up to just under 2GB in size.
You can use DATALENGTH() function to determine the length of the column content.
For example:
SELECT DATALENGTH(CompanyName), CompanyName
FROM Customers
CREATE FUNCTION [dbo].[FileDataSizeUnit_FN] (#FileData VARBINARY(MAX))
RETURNS VARCHAR(3)
AS
BEGIN
DECLARE #Unit VARCHAR(3),
#ByteLen AS NUMERIC(16,2)
SET #ByteLen = ISNULL(DATALENGTH(#FileData),0)
SET #Unit = CASE WHEN #ByteLen < 1000 THEN 'B'
WHEN #ByteLen < 100000 THEN 'KB'
WHEN #ByteLen < 1000000000 THEN 'MB'
ELSE 'GB' END
RETURN #Unit
END
GO
CREATE FUNCTION [dbo].[FileDataSize_FN] (#FileData VARBINARY(MAX))
RETURNS NUMERIC(16,2)
AS
BEGIN
DECLARE #Size AS NUMERIC(16,2),
#ByteLen AS NUMERIC(16,2)
SET #ByteLen = ISNULL(DATALENGTH(#FileData),0)
SET #Size = CASE WHEN #ByteLen <1000 THEN #ByteLen
WHEN #ByteLen < 100000 THEN #ByteLen/1024.0
WHEN #ByteLen < 1000000000 THEN #ByteLen/1024.0/1024
ELSE CAST(#ByteLen/1024.0/1024/1024 AS NUMERIC(16,2)) END
RETURN #Size
END
GO
SELECT dbo.FileDataSize_FN(F.FileData) AS Size,
dbo.FileDataSizeUnit_FN(F.FileData) AS SizeUnit
FROM dbo.Files_Tbl F
Related
I have to generate a very long procedure every time for a reporting system, so i created a template for my procedure and replacing the parts are needed to, but i could do it with Concat or +(&)
for example:
set #query = '... and (
--#InnerQueries
)'
set #query = replace(#query,'--#InnerQueries',#otherValues)
vs
set #query += ' and exists (...)'
if(#xxx is not null)
set #query += 'and not exists (...)'
with replace approach it's more readable and maintainable for me, but for sake of optimization, what about Concat and attaching string together?
with replace: there are a lot of searching but less string creation
and with concat: lot's of string creation but no searching
so any idea?
I assume you're talking about using CONCAT or REPLACE to build an SQL then run it. If ultimately you'll process fewer than 100 REPLACEments, I'd go with that approach rather than CONCAT because it's more readable.
If however, you're talking about using concat/replace to create report output data and you will e.g. be carrying out 100 REPLACE operations per row on a million rows, I'd do the CONCAT route
update 2:
there could be something missing here:
if i change first variable :#sourceText_Replace
to a max value of 8000 character, and continue to add to it:
set #sourceText_Replace += '8000 character length'
set #sourceText_Replace +=#sourceText_Replace
set #sourceText_Replace +=#sourceText_Replace
set #sourceText_Replace +=#sourceText_Replace
set #sourceText_Replace +=#sourceText_Replace
set #sourceText_Replace +=#sourceText_Replace
set #sourceText_Replace +=#sourceText_Replace
it works fine, even if go up until: 16384017 character length
so any idea here is as good as mine
orginal answer:
to summarize (and if i didnt make any mistakes):
if you are searching in a long text, dont even think about using replace, it took seconds not milliseconds, but for concat obviously does not make any difference
in the blew code, in first try(small text), i just used variables default values and did not append to them,
but for second try(long Text) , i just append result from previous loop run
for long text, i did not bothered to run the loop more than 20 time, because it took over minutes.
smallText: set #destSmallText_Replace =
longText: set #destSmallText_Replace +=
here is the code for test:
SET NOCOUNT ON
drop table if exists #tempReplace
drop table if exists #tempConcat
create table #tempReplace
(
[txt] nvarchar(max) not null
)
create table #tempConcat
(
[txt] nvarchar(max) not null
)
declare #sourceText_Replace nvarchar(max) = 'small1 text to replace #textToBeReplaced after param text'
declare #text_Replace nvarchar(max) = #sourceText_Replace
declare #textToSearch nvarchar(max) = '#textToBeReplaced'
declare #textToReplace nvarchar(max) = 'textToBeReplaced'
declare #concat_Start nvarchar(max) = 'small1 text to replace'
declare #concat_End nvarchar(max) = 'after param text'
declare #text_Concat nvarchar(max) = #concat_Start
declare #whileCounter int =0
declare #maxCounter int = 5
declare #startTime datetime = getdate();
declare #endTime datetime = getdate();
begin
set #startTime = getDate();
while(#whileCounter <=#maxCounter)
begin
--long text
set #text_Replace += replace(#sourceText_Replace,#textToSearch,#textToReplace + convert(nvarchar(10), #whileCounter)) + #textToSearch
--small text
--set #text_Replace = replace(#sourceText_Replace,#textToSearch,#textToReplace + convert(nvarchar(10), #whileCounter)) + #textToSearch
--print #destSmallText_Replace
insert into #tempReplace values(#text_Replace)
set #whileCounter+=1
end
set #endTime = getDate();
print 'passedTime ' + Convert(nvarchar(20), DATEPART(millisecond, #endTime) - DATEPART(millisecond, #startTime))
end
begin
set #whileCounter = 0;
set #startTime = getDate();
while(#whileCounter <=#maxCounter)
begin
set #text_Concat += concat(#concat_Start,#textToReplace + convert(nvarchar(10), #whileCounter),#concat_End) + #textToSearch
--print #sourceSmallText_Concat
insert into #tempConcat values(#text_Concat)
set #whileCounter+=1
end
set #endTime = getDate();
print 'passedTime ' + Convert(nvarchar(20), DATEPART(millisecond, #endTime) - DATEPART(millisecond, #startTime))
end
I want to make an algorithm for generate next series number by specified last series number in sql like below:
Last Number Next Number
> AAAA095 AAAA096
> AAAA999 AAAB001
> AAAB001 AAAB002
> AAAZ999 AABA001
After some try, Finally i got an algorithm & create it to SQL Scalar-valued function for this question as below
CREATE FUNCTION GetNextSeries ( #lastSeriesNo VARCHAR(8))
RETURNS VARCHAR(8)
AS
BEGIN
DECLARE #nextSeriesNo VARCHAR(8)
DECLARE #CHAR1 CHAR=SUBSTRING(#lastSeriesNo,1,1)
DECLARE #CHAR2 CHAR=SUBSTRING(#lastSeriesNo,2,1)
DECLARE #CHAR3 CHAR=SUBSTRING(#lastSeriesNo,3,1)
DECLARE #CHAR4 CHAR=SUBSTRING(#lastSeriesNo,4,1)
DECLARE #n INT=SUBSTRING(#lastSeriesNo,5,3)
SET #n = #n + 1
IF(#n>999)
BEGIN
SET #n=1
IF(#CHAR4<>'Z')
BEGIN
SET #CHAR4=CHAR(UNICODE(#CHAR4)+1)
END
ELSE IF(#CHAR3<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3=CHAR(UNICODE(#CHAR3)+1)
END
ELSE IF(#CHAR2<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3='A'
SET #CHAR2=CHAR(UNICODE(#CHAR2)+1)
END
ELSE IF(#CHAR1<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3='A'
SET #CHAR2='A'
SET #CHAR1=CHAR(UNICODE(#CHAR1)+1)
END
END
SET #nextSeriesNo=#CHAR1+#CHAR2+#CHAR3+#CHAR4+(CASE LEN(#n) WHEN 1 THEN '00' WHEN 2 THEN '0' ELSE '' END)+convert(VARCHAR(3),#n)
RETURN #nextSeriesNo
END
This is more of a solution than question.
I've looked at many threads to find a good solution for converting decimal hours into 'hh:mm' format but only got bits and pieces here and there. So thought, I'd share my solution if it's useful for anyone.
Mods - please feel free to optimize/refine my function.
--this will convert 45.50 to '45:30' or -45.50 to '-45:30'
CREATE FUNCTION [dbo].[GetTimeFromNumericValue](#numerichours numeric(24,6))
RETURNS varchar(6) --Only string takes negative
AS
BEGIN
Declare #returnvalue numeric(24,6) ;
Declare #left varchar(10);
Declare #right varchar(10);
If(#numerichours is NULL OR #numerichours = 0.0 )
Begin
Return '';
End
Else if (#numerichours<0)
Begin
set #numerichours = ABS(#numerichours)
Return '-' + RIGHT('0'+Convert(varchar, FLOOR(#numerichours)),2) +':' + RIGHT('0'+Convert(varchar,Convert(int,((#numerichours - FLOOR(#numerichours)) * 60))),2)
End
Else
Begin
Return RIGHT('0'+Convert(varchar, FLOOR(#numerichours)),2) +':' + RIGHT('0'+Convert(varchar,Convert(int,((#numerichours - FLOOR(#numerichours)) * 60))),2)
End
Return '';
End
Thank you in advance for your help here.
I want to insert incremental numbers as strings to load some bulk test numbers into a db, here is what i'm using:
Declare
#Serialcounter bigint
set #Serialcounter = 0
while #Serialcounter < 10
insert into [TrackTrace].[dbo].[TAB_ELEMENT] ([Serial], [Batch], [Batch_Id], [QCSample], [StationID])
values(Convert(varchar(60), #Serialcounter), 'test', 8989, 0, 1)
set #Serialcounter = (#Serialcounter + 1)
but when I do this it does not increment the counter and I just insert duplicate numbers and do not stop. I think my problem is that my variable is incremented outside of the while loop, but I am not sure how to rectify this.
Declare
#Serialcounter bigint
set #Serialcounter = 0
while #Serialcounter < 10
BEGIN
PRINT #Serialcounter
--insert into [TrackTrace].[dbo].[TAB_ELEMENT]
--([Serial]
--,[Batch]
--,[Batch_Id]
--,[QCSample]
--,[StationID])
--Values(Convert(varchar(60),#Serialcounter),'test',8989,0,1)
set #Serialcounter = (#Serialcounter +1 )
END
You not giving begin and end so as for all loops only first statement is considered
I was missing BEGIN and END statements
DECLARE
#Serialcounter BIGINT
SET #Serialcounter = 0
WHILE #Serialcounter < 10
BEGIN -- here
INSERT INTO [TrackTrace].[dbo].[TAB_ELEMENT]
([Serial]
,[Batch]
,[Batch_Id]
,[QCSample]
,[StationID])
VALUES(Convert(varchar(60),#Serialcounter),'test',8989,0,1)
SET #Serialcounter = (#Serialcounter +1 )
END -- and here
I want to create automatic code example:
B001, B002, B003, B004 .....
I have create the function for that:
CREATE FUNCTION AUTO_CODE()
RETURNS CHAR (4)
AS
BEGIN
DECLARE #KODE CHAR(4)
SELECT #KODE = COUNT (KODE_BARANG)FROM BARANG
IF #KODE>0
BEGIN
SELECT #KODE = RIGHT(KODE_BARANG,4) FROM BARANG
SET #KODE = #KODE+1
END
ELSE SET #KODE=1
RETURN 'B' + LEFT('00',3-LEN(#KODE))+(#KODE)
END
The function above only works for B001 through B010, beyond that it was back to B001. It won't work for B011, B012 or B120.
After that I have try to do with if else:
...
DECLARE KODENYA CHAR (5)
IF #KODE >= 0 AND #KODE <=9
BEGIN
SET #KODENYA = 'B' + LEFT('00',4-LEN(#KODE))+(#KODE)
END
ELSE IF #KODE >= 10 AND #KODE <=99
BEGIN
SET #KODENYA = 'B' + LEFT('0',4-LEN(#KODE))+(#KODE)
END
ELSE IF #KODE >= 100 AND #KODE <=999
BEGIN
SET #KODENYA = 'B' + LEFT('',4-LEN(#KODE))+(#KODE)
END
RETURN #KODENYA
The result is still the same and somehow I get #KODE if it was beyond 9 it return to null and SQL SERVER read it as 0.
Is there another way to create this kind of code in SQL SERVER?
There is no need for multiple if/case just simple FORMAT:
CREATE TABLE #tab(KODE INT);
INSERT INTO #tab(KODE) VALUES (1),(2),(10),(99),(101),(100),(999);
SELECT FORMAT(KODE, 'B00#')
FROM #tab;
LiveDemo
You can easily tweak it for longer codes by changing format string 'B000#'
And in your case:
CREATE FUNCTION [dbo].[AUTO_CODE]()
RETURNS CHAR(4)
AS
BEGIN
DECLARE #KODE INT = (SELECT COUNT(KODE_BARANG)FROM BARANG);
RETURN FORMAT(#KODE, 'B00#');
END
Warning:
You function may return duplicates/create gaps when many concurrent calls occur.
SqlFiddleDemo
Depending on your needs you may consider adding calculated column to your BARANG table:
CREATE TABLE BARANG(ID INT IDENTITY(1,1) PRIMARY KEY,
col2 VARCHAR(120) NOT NULL,
...
KODE AS (FORMAT(ID, 'B00#'))
);