Inserting images from file path -- Not getting value on the select statement - sql-server-2008

DECLARE #imgString varchar(800)
DECLARE #insertString varchar(3000)
DECLARE #imgNumber int
Declare #imgName varchar(100)
SET #imgNumber = 1
WHILE #imgNumber<> 101
BEGIN
SET #imgName = 'SELECT (items) FROM dbo.building_piclink'
SET #imgString = 'C:\Documents and Settings\Administrator\Desktop\photos\' + #imgName
SET #insertString = 'INSERT INTO dbo.building__ATTACH (DATA)
SELECT * FROM OPENROWSET(BULK N''' + #imgString + ''', SINGLE_BLOB) as tempImg'
SET #imgNumber = #imgNumber + 1
END
GO
I am having problems with the #imgName. I can't figure out how to get the value from the select statement not the (items) like below:
C:\Documents and Settings\Administrator\Desktop\photos\SELECT (items) FROM dbo.building_piclink
Thank you!

Your code has several problems:
1) You're selecting a file name from the view - but what if that view contains more than one entry?? Which filename are you selecting?? Your current code first of all doesn't work at all the way it is, and even if it were working - you're still potentially selecting hundreds of filenames into a single variable - which of course won't work....
So you'll need to fix this here first:
SET #imgName = 'SELECT (items) FROM dbo.building_piclink'
First of all - loose the single quotes:
SELECT #imgName = (items) FROM dbo.building_piclink
But now - do you have a unique ID that you can select for? Or do you want to get just the first entry (whatever that is) ??
So either you need:
SELECT #imgName = ImageFileName FROM dbo.building_piclink WHERE ..........
and fill in that WHERE clause with a condition that guarantees to return just a single row, or use TOP 1:
SELECT TOP (1) #imgName = ImageFileName FROM dbo.building_piclink
In that case - you'll just get exactly one filename - if you don't specify an ORDER BY, then there's no guarantee what you'll get - maybe you'll want to add a ORDER BY DueDate or something to prioritize which file names you get first.
2) Your code for loading the image data is non workable, either - what you need to do is build up the SQL statement as a string, and then execute it (called dynamic SQL) - something like this:
SET #imgString = 'C:\Documents and Settings\Administrator\Desktop\photos\' + #imgName
SET #insertString =
'INSERT INTO dbo.building__ATTACH (DATA)
SELECT * FROM OPENROWSET(BULK N''' + #imgString + ''', SINGLE_BLOB) as tempImg'
EXEC(#insertString) -- actually execute your SQL statement!
With these two fixes, you should be on the way to get this thing working

Related

Mysql function not returning the expected result

As I have mentioned in my question title below Mysql function returns null always :
CREATE DEFINER=`root`#`localhost` FUNCTION `nextCode`(tbl_name VARCHAR(30), prv_code VARCHAR(30)) RETURNS varchar(30) CHARSET utf8
READS SQL DATA
BEGIN
DECLARE nxtCode VARCHAR(30);
SELECT ds.prefix, ds.suffix, ds.is_used, ds.next_number, CHAR_LENGTH(ds.pattern)
INTO #prefix, #suffix, #isUsed, #nxtNum, #pLength
FROM ths_inventory.doc_sequnce ds WHERE ds.`table_name` = tbl_name;
SET nxtCode = CONCAT(#prefix, LPAD((CASE WHEN #isUsed
THEN
(ExtractNumber(prv_code) + 1)
ELSE
(#nxtNum)
END
), #pLength,'0'), #suffix);
RETURN nxtCode;
END
But once I change the below line :
CONCAT(#prefix, LPAD((CASE WHEN #isUsed
THEN
(ExtractNumber(prv_code) + 1)
ELSE
(#nxtNum)
END
), #pLength,'0'), #suffix)
To some static values like below :
CONCAT('PR', LPAD((CASE WHEN true
THEN
(ExtractNumber(prv_code) + 1)
ELSE
(5)
END
), 6,'0'), '')
function start returning values accordingly.
Here is how I call my function :
nextCode('item','PR000002');
UPDATE:
I defined this function to get the next possible code for Item table :
According to my requirement the next possible code should be PR000000005.
But instead of getting it, I always get empty result .
SELECT nextCode('item',(SELECT `code` FROM item ORDER BY id DESC LIMIT 1)) AS next_code;
Any help would be appreciable.
Run a query that uses the function, and then...
SELECT #prefix, #suffix, #isUsed, #nxtNum, #pLength;
...to inspect the values. The # prefix means these are user-defined variables, so they have session scope, not program scope, and will still hold their values after the funcfion executes.
This should help pinpoint your problem.
But, you have two other problems you will need to solve after that.
SELECT ... INTO does not set the target variables when no row matches the query, so once you fix your issue, you will get very wrong results if you pass in arguments that don't match anything.
To resolve this, the function needs to set all these variables to null before the SELECT ... INTO query.
SET #prefix = NULL, #suffix = NULL, #isUsed = NULL, #nxtNum = NULL, #pLength = NULL;
See https://dba.stackexchange.com/a/35207/11651.
Also, your function does not handle concurrency, so two threads trying to find the "next" value for the same table, concurrently, will produce the same answer, so you will need to insure that your code handles this correctly with unique constraints and transactions or other appropriate locks.

MySQL user-defined function returns incorrect value when used in a SELECT statement

I met a problem when calling a user-defined function in MySQL. The computation is very simple but can't grasp where it went wrong and why it went wrong. Here's the thing.
So I created this function:
DELIMITER //
CREATE FUNCTION fn_computeLoanAmortization (_empId INT, _typeId INT)
RETURNS DECIMAL(17, 2)
BEGIN
SET #loanDeduction = 0.00;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
INTO #totalAmount, #periodicDeduction, #totalInstallments, #deductionFlag
FROM loans_table
WHERE TypeId = _typeId AND EmpId = _empId;
IF (#deductionFlag = 1) THEN
SET #remaining = #totalAmount - #totalInstallments;
IF(#remaining < #periodicDeduction) THEN
SET #loanDeduction = #remaining;
ELSE
SET #loanDeduction = #periodicDeduction;
END IF;
END IF;
RETURN #loanDeduction;
END;//
DELIMITER ;
If I call it like this, it works fine:
SELECT fn_computeLoanAmortization(3, 4)
But if I call it inside a SELECT statement, the result becomes erroneous:
SELECT Id, fn_computeLoanAmortization(Id, 4) AS Amort FROM emp_table
There's only one entry in the loans_table and the above statement should only result with one row having value in the Amort column but there are lots of random rows with the same Amort value as the one with the matching entry, which should not be the case.
Have anyone met this kind of weird dilemma? Or I might have done something wrong from my end. Kindly enlighten me.
Thank you very much.
EDIT:
By erroneous, I meant it like this:
loans_table has one record
EmpId = 1
TypeId = 2
PeriodicDeduction = 100
TotalAmount = 1000
TotalInstallments = 200
DeductionFlag = 1
emp_table has several rows
EmpId = 1
Name = Paolo
EmpId = 2
Name = Nikko
...
EmpId = 5
Name = Ariel
when I query the following statements, I get the correct value:
SELECT fn_computeLoanAmortization(1, 2)
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table WHERE EmpId = 1
But when I query this statement, I get incorrect values:
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table
Resultset would be:
EmpId | Amort
--------------------
1 | 100
2 | 100 (this should be 0, but the query returns 100)
3 | 100 (same error here)
...
5 | 100 (same error here up to the last record)
Inside your function, the variables you use to retrieve the values from the loans_table table are not local variables local to the function but session variables. When the select inside the function does not find any row, those variables still have the same values as from the previous execution of the function.
Use real local variables instead. In order to do that, use the variables names without # as a prefix and declare the variables at the beginning of the function. See this answer for more details.
I suspect the problem is that the variables in the INTO are not re-set when there is no matching row.
Just set them before the INTO:
BEGIN
SET #loanDeduction = 0.00;
SET #totalAmount = 0;
SET #periodicDeduction = 0;
SET #totalInstallments = 0;
SET #deductionFlag = 0;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
. . .
You might just want to set them to NULL.
Or, switch your logic to use local variables:
SET v_loanDeduction = 0.00;
SET v_totalAmount = 0;
SET v_periodicDeduction = 0;
SET v_totalInstallments = 0;
SET v_deductionFlag = 0;
And so on.

Write to database from case results

I want to update a databased based upon results from a case, however my "If" statement doesn't seem to pull information from the right table.
declare #dt datetime
set #dt = GETDATE()
select
Ugenummer = datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1,
case when (datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1) % 2 = 1
then 'ulige' else 'lige' end Ugelighed;
The above code gets the weeknumber (ugenummer) and determines whether it's odd or even (Ulige/lige)
IF Ugelighed = ulige and datepart(dw,#dt) = 1
THEN
UPDATE laeger
SET Antal=1
WHERE Navn=Lægenavn
I would like to use the information from the first code to update a database in a SQL 2008 server
You aren't using Ugenummer so I edited it out. Also created a variable for Ugelighed, you forgot to create one:
declare #dt datetime
set #dt = GETDATE()
declare #Ugelighed VARCHAR(5);
select
#Ugelighed=case when (datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1) % 2 = 1
then 'ulige' else 'lige' end;
In the following statements I used variable #Ugelighed to compare to ulige however it is a VARCHAR so you need to enclose it in single quotes (''). Same for Lægenavn, it is a VARCHAR so enclose it in single quotes:
IF #Ugelighed = 'ulige' and datepart(dw,#dt) = 1
UPDATE laeger
SET Antal=1
WHERE Navn='Lægenavn'
Personally I would have created a BIT field for #Ugelighed since even/odd can be captured as a simple boolean rather than text.

How to get a value from func/sp to a case statement using dynamic SQL?

hoping someone might be able to help me with a bit of an issue. Essentially i'm trying to get a rough size of all of the fields in my database as i'd like to do some math on it to guesstimate what the size will be with a compression technique applied to it.
I can do this for most fields by looking at the datatype and using the number of rows to get the number of bytes it's taking up. However on something like a varchar(max) field this is not as easy and so i decided to approach this by getting the average length within the column and multiplying by number of rows. But i've hit a snag which i'll describe below.
I have the following stored proc (i tried a function too but you can't call dynamic SQL from a function).
CREATE PROCEDURE dbo.getFieldSize(#column varchar(255), #table varchar(255), #ret decimal(15,7) OUTPUT)
AS
BEGIN
DECLARE #lengthSQL varchar(50)
/SET #lengthSQL = 'SELECT #ret = AVG(DATALENGTH(' + #column + ')) FROM [' + #table +']'/
SET #lengthSQL = 'SELECT #ret = AVG(DATALENGTH(' + #column + ')) FROM ' + #table
exec sp_executesql #lengthSQL
RETURN #ret
END
GO
And then i call it using...
SELECT b.TABLE_SCHEMA as 'Schema',
CASE WHEN DATA_TYPE IN ('nvarchar') AND CHARACTER_MAXIMUM_LENGTH <> -1 AND c.distinctItems <> 0 AND c.totalCount <> 0 THEN exec('select max(len(' + b.TABLE_CATALOG + ' + '.' + ' + b.COLUMN_NAME + '))')
FROM ....
The above is basically just checking to make sure it is a varchar(max) field and contains some values within the column. I then try and execute the SP and pass the column name and table name for which i need the avg length but i get the following error.
Msg 156, Level 15, State 1, Line 57
Incorrect syntax near the keyword 'exec'.
I learned you cannot call a dynamic SQL from a function and you cannot call a SP from a CASE statement. So at this point it seems like it's a catch 22 and i cannot do what i need using SQL. Can anyone think of any workarounds or i'm I out of luck on this?
Actually, you can do Dynamic SQL in a scalar UDF, it just needs to be a SQLCLR UDF ;-). But this is fairly simple to do using the in-process / internal connection (i.e. SqlConnection("Context Connection = true;");). Meaning, the assembly can be set to SAFE.
Also, object / column / index names are all NVARCHAR. And objects (if not also the others) are declared as sysname which is an alias for NVARCHAR(128). Just FYI.
So, something like the following (which I have tested and it does work):
[Microsoft.SqlServer.Server.SqlFunction(Name = "GetAvgBytes",
IsDeterministic = false, IsPrecise = true, DataAccess = DataAccessKind.Read)]
public static SqlInt32 GetAvgBytes([SqlFacet(MaxSize = 128)] SqlString TableName,
[SqlFacet(MaxSize = 128)] SqlString ColumnName)
{
int _AvgBytes = -1;
SqlConnection _Connection = new SqlConnection("Context Connection = true;");
SqlCommand _Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SELECT #AvgBytes = AVG(DATALENGTH(" + ColumnName.Value
+ ")) FROM " + TableName.Value + " WITH (NOLOCK);";
SqlParameter _Param = new SqlParameter("#AvgBytes", DbType.Int32);
_Param.Direction = ParameterDirection.Output;
_Command.Parameters.Add(_Param);
try
{
_Connection.Open();
_Command.ExecuteNonQuery();
_AvgBytes = (int)_Param.Value;
}
finally
{
_Connection.Close();
}
return _AvgBytes;
}

Updating column values as per our format

There are two types of records in my Db such as MS-NW and CS in the same column of table DICIPLINE I want to wrap if its CS (ANY TWO STRING LIKE CS,TE OR THE LIKE) then wrap it to BS(CS) (OR BS(TE) ETC) or if its MS-NW (Or MS-CS, MS-TE and the like) then wrap it to MS(NW) from the column dicipline.
I updated for two strings successfully and following is the query for that kindly let me know how can i do it for values like MS-NW OR MS-CS and convert it to the format like MS(NW) from following query .
UPDATE DEG set DICIPLINE = concat("BS(",DICIPLINE,")") where CHAR_LENGTH(DICIPLINE) = 2
The below query helps you to update your data.
update deg set DISIPLINE = if(length(DISIPLINE)= 2,concat('BC(',DISIPLINE,')')
,concat('MS(',substr(DISIPLINE, 4,4),')'));
See Sqlfiddle demo.
For safety, create a temporary column of same type and perform an update like this:
UPDATE deg
SET dicipline_temp = CASE
WHEN CHAR_LENGTH(dicipline) = 2
THEN CONCAT('BS(', dicipline, ')')
WHEN CHAR_LENGTH(dicipline) = 5 AND SUBSTRING(dicipline, 3, 1) = '-'
THEN CONCAT(REPLACE(dicipline, '-', '('), ')')
END
WHERE CHAR_LENGTH(dicipline) = 2 OR (CHAR_LENGTH(dicipline) = 5 AND SUBSTRING(dicipline, 3, 1) = '-')
If results are acceptable, update the actual column.