Flutter Floor "duplicate column name" - sql

I'm facing this exact error using the Floor package in Flutter Unhandled Exception: DatabaseException(Error Domain=FMDatabase Code=1 "duplicate column name: kit" and I can't see exactly where i've made a mistake, here's my full database code:
The error happens when I currently have version 5 of the database running and I attempt to run a build of the project that has version 6.
#Database(version: 6, entities: [Player, SavedTeam, Design, Kit, KitPattern])
abstract class LocalDatabase extends FloorDatabase {
PlayerDao get playerDao;
SavedTeamDao get savedTeaDao;
DesignDao get designDao;
KitDao get kitDao;
KitPatternDao get kitPatternDao;
}
final migration1to2 = Migration(1, 2, (database) async {
await database.execute('CREATE TABLE IF NOT EXISTS `SavedTeam` '
'(`id` TEXT NOT NULL, '
' `pitchFilePath` TEXT NOT NULL,'
' `playerOne` TEXT NOT NULL,'
' `playerTwo` TEXT NOT NULL, '
' `playerThree` TEXT NOT NULL, '
' `playerFour` TEXT NOT NULL, '
' `playerFive` TEXT NOT NULL, '
' `playerSix` TEXT NOT NULL, '
' `playerSeven` TEXT NOT NULL, '
' `playerEight` TEXT NOT NULL, '
' `playerNine` TEXT NOT NULL, '
' `playerTen` TEXT NOT NULL, '
' `playerEleven` TEXT NOT NULL, '
' `playerOneOffset` TEXT NOT NULL, '
' `playerTwoOffset` TEXT NOT NULL, '
' `playerThreeOffset` TEXT NOT NULL, '
' `playerFourOffset` TEXT NOT NULL, '
' `playerFiveOffset` TEXT NOT NULL, '
' `playerSixOffset` TEXT NOT NULL, '
' `playerSevenOffset` TEXT NOT NULL, '
' `playerEightOffset` TEXT NOT NULL, '
' `playerNineOffset` TEXT NOT NULL, '
' `playerTenOffset` TEXT NOT NULL, '
' `playerElevenOffset` TEXT NOT NULL, '
' `kitColor` TEXT NOT NULL, '
' `pitch` TEXT NOT NULL, '
'PRIMARY KEY (`id`))');
});
final migration2to3 = Migration(2, 3, (database) async {
await database.execute('CREATE TABLE IF NOT EXISTS `Design` '
'(`id` TEXT NOT NULL, '
' `pattern` TEXT NOT NULL, '
' `patternColor` TEXT NOT NULL, '
' `baseKitColor` TEXT NOT NULL, '
'PRIMARY KEY (`id`))');
await database.execute('ALTER TABLE SavedTeam ADD COLUMN design TEXT');
await database.execute('ALTER TABLE SavedTeam ADD COLUMN showPhotos INTEGER');
});
final migration3to4 = Migration(3, 4, (database) async {
await database.execute('CREATE TABLE IF NOT EXISTS `Kit` '
'(`id` TEXT NOT NULL, '
' `productId` TEXT NOT NULL, '
' `assetPath` TEXT NOT NULL, '
'PRIMARY KEY (`id`))');
});
final migration4to5 = Migration(4, 5, (database) async {
await database.execute('ALTER TABLE SavedTeam ADD COLUMN kit TEXT');
});
final migration5to6 = Migration(5, 6, (database) async {
await database.execute('CREATE TABLE IF NOT EXISTS `KitPattern` '
'(`id` TEXT NOT NULL, '
' `productId` TEXT NOT NULL, '
' `assetPath` TEXT NOT NULL, '
'PRIMARY KEY (`id`))');
});
final localDatabase = $FloorLocalDatabase
.databaseBuilder('local_database.db')
.addMigrations([
migration1to2,
migration2to3,
migration3to4,
migration4to5,
migration5to6
]).build();

Although I couldn't figure out exactly why SQL was attempting to run an old migration (4 to 5) I have fixed the issue by wrapping the migration in a try catch like so:
final migration4to5 = Migration(4, 5, (database) async {
try {
await database.execute('ALTER TABLE SavedTeam ADD COLUMN kit TEXT');
} on Exception {
print("migration 4to5 error");
}
});

Related

plpgsql function concat optionnal args return error

I want to concat optionnal arguments separated by AND and return a varchar of those concatenate argument(s) that are not null.
CREATE OR REPLACE FUNCTION shop_apply_search_filters(price_min INTEGER DEFAULT NULL, price_max INTEGER DEFAULT NULL, ecom_id INTEGER DEFAULT NULL,
cat_1 VARCHAR DEFAULT NULL, cat_2 VARCHAR DEFAULT NULL)
RETURNS VARCHAR AS
$$
DECLARE final_filters VARCHAR(500);
BEGIN
IF price_min IS NOT NULL THEN
SELECT CONCAT('price<',price_min) AS n_price_min;
final_filters := n_price_min;
END IF;
IF price_max IS NOT NULL THEN
SELECT CONCAT('price>',price_max) AS n_price_max;
final_filters := CONCAT(final_filters,' AND ', n_price_max);
END IF;
IF ecom_id IS NOT NULL THEN
SELECT CONCAT('ecom_id=',ecom_id) AS n_ecom_id;
final_filters := CONCAT(final_filters,' AND ', n_ecom_id);
END IF;
IF cat_1 IS NOT NULL THEN
SELECT CONCAT('category_1:',cat_1) AS n_cat_1;
final_filters := CONCAT(final_filters,' AND ', n_cat_1);
END IF;
IF cat_2 IS NOT NULL THEN
SELECT CONCAT('category_2:',cat_2) AS n_cat_2;
final_filters := CONCAT(final_filters,' AND ', n_cat_2);
END IF;
RETURN final_filters;
END;
$$
LANGUAGE PLPGSQL;
The output of SELECT shop_apply_search_filters(10) would be a string like 'price > 10'.
Is it possible to pass args name when calling function ? In order to be able to distinguish price_min and price_max if only one of them is passed.
Is it possible to append not null args to a list and then JOIN list elements with an AND ?
How would you do ?
EDIT
I removed the SELECT() when CONCAT() to avoid error. But I have a new one :
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function shop_apply_search_filters(integer,integer,integer,character varying,character varying) line 5 at SQL statement
SQL state: 42601
EDIT
I tried :
create or replace function shop_apply_search_filters(
price_min integer default null,
price_max integer default null,
ecom_id integer default null,
cat_1 text default null,
cat_2 text default null)
returns text as
$$
select concat_ws(
' and ',
'price < ' || price_min,
'price > ' || price_max,
'ecom_id = ' || ecom_id,
'category_1 = ' || cat_1,
'category_2 = ' || cat_2
);
$$
language sql;
It works fine with all arguments passed :
SELECT shop_apply_search_filters(10,10,10,'cat_1','cat_2')
How to handle when not all arguments are passsed ?
SELECT shop_apply_search_filters(10,10,'cat_1','cat_2')
ERROR: invalid input syntax for integer: "cat_1"
LINE 1: SELECT shop_apply_search_filters(10,10,'cat_1','cat_2')
^
SQL state: 22P02
Character: 40
SELECT shop_apply_search_filters(10,10)
ERROR: function shop_apply_search_filters(integer, integer) is not unique
LINE 1: SELECT shop_apply_search_filters(10,10)
^
HINT: Could not choose a best candidate function. You might need to add explicit type casts.
SQL state: 42725
Character: 8
Why not just use concat_ws() to join the whole string at once?
concat_ws(
' and ',
'price < ' || price_min,
'price > ' || price_max,
'ecom_id = ' || ecom_id,
'category_1 = ' || cat_1,
'category_2 = ' || cat_2
)
You could then simplify the whole procedure as:
create or replace function shop_apply_search_filters(
price_min integer default null,
price_max integer default null,
ecom_id integer default null,
cat_1 text default null,
cat_2 text default null)
returns text as
$$
select concat_ws(
' and ',
'price < ' || price_min,
'price > ' || price_max,
'ecom_id = ' || ecom_id,
'category_1 = ' || cat_1,
'category_2 = ' || cat_2
);
$$
language sql;

Loop through table with multiple rows and send one email

As a noob, I am really battling with this.
I have a table as follows
SELECT [AuditFieldID]
,[CompanyRuleID]
,[CompanyRule]
,[VipUserName]
,[EffectiveDate]
,[FieldName]
,[SourceCode]
,[Action]
,[AccountNoOldValue]
,[AccountNoNewValue]
,[AccountTypeOldValue]
,[AccountTypeNewValue]
,[BankOldValue]
,[BankNewValue]
,[BranchOldValue]
,[BranchNewValue]
,[AccountHolderOldValue]
,[AccountHolderNewValue]
FROM [SageStaging].[MASSMART].[AuditCondensed]
There are 5 rows in the table for each employee. The first 5 fields contain the same data, and then the fieldname field, contains a different record type.
So you will have
Auditfieldid = 111111
CompanyRuleID = 12
CompanyRule = Walmart
VipUsername = john.doe
EffectiveDate = date()
Fieldname = 'Account Holder Name'
SourceCode = 1234 - John Doe
Action = I
AccountNoOldValue = NULL
AccountNoNewValue = NULL
AccountTypeOldValue = NULL
AccountTypeNewValue = NULL
BankOldValue = NULL
BankNewValue = NULL
BranchOldValue = NULL
BranchNewValue = NULL
AccountHoldOldValue = ''
AcccountHolderNewValue = 'John Doe'
There are five field name types:
FieldName = 'Account Holder Name'
FieldName = 'Account Number'
FieldName = 'Account Type'
FieldName = 'Bank'
FieldName = 'Bank Branch'
If the FieldName is = 'Account Holder' the record will have values in AccountHoldOldValue and AccountHoldNewValue
If FieldName is = 'Account Number' the record will have values in AccountNoOldValue and AccountNoNewValue
and so forth. So all in all you have 5 records of different fieldname types and in the row the appropriate value field populated according to the fieldname type.
I need to send an email with these values consolidated. So one email creating the following:
SET #MailSubject = 'Banking Details Change Notification for Employee' + ' ' + #SOURCECODE
SET #MessageBody = '<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title></title>
</head>
<body>
<br>
The following bank details have been changed:
<br>
<br>
Date Changed: ' + #EFFECTIVEDATE + '<br>' +
' Company: ' + #COMPANYRULE + '<br>' +
' Username: ' + #VIPUSERNAME + '<br>' +
' Employee Details: ' + #SOURCECODE + '<br>' +
' Action: ' + #ACTION + '<br>' +
' Account Holder: ' + ' Old Value: ' + #ACCOUNTHOLDEROLDVALUE + ' New Value: ' + #ACCOUNTHOLDERNEWVALUE + '<br>' +
' Account Number: ' + ' Old Value: ' + #ACCOUNTNOOLDVALUE + ' New Value: ' + #ACCOUNTNONEWVALUE + '<br>' +
' Account Type: ' + ' Old Value: ' + #ACCOUNTTYPEOLDVALUE + ' New Value: ' + #ACCOUNTTYPENEWVALUE + '<br>' +
' Bank: ' + ' Old Value: ' + #BANKOLDVALUE + ' New Value: ' + #BANKNEWVALUE + '<br>' +
' Bank Branch: ' + ' Old Value: ' + #BRANCHOLDVALUE + ' New Value: ' + #BRANCHNEWVALUE + '<br>' +
'<br>
<br>
<b>
Please do not respond to this email. If you have any questions regarding this email, please
contact your payroll administrator <br>
<br>
<br>
</body>'
I cannot seem to be able to figure out how to send just one email with all the necessary fields consolidated.
I seem to get five emails with blanks in all the fields, just the first four fields of the record gets populated.
This query should give you one record for each email.
select
a.Auditfieldid,
a.CompanyRuleID,
a.CompanyRule,
a.VipUsername,
a.EffectiveDate,
a.AccountHolderOldValue,
a.AccountHolderNewValue,
b.AccountNoOldValue,
b.AccountNoNewValue,
c.AccountTypeOldValue,
c.AccountTypeNewValue,
d.BankOldValue,
d.BankNewValue,
e.BranchOldValue,
e.BranchNewValue
from
(
select
Auditfieldid,
CompanyRuleID,
CompanyRule,
VipUsername,
EffectiveDate,
AccountHolderOldValue,
AccountHolderNewValue
from
SageStaging.MASSMART.AuditCondensed
where
FieldName = 'Account Holder Name'
) a
join
(
select
Auditfieldid,
CompanyRuleID,
CompanyRule,
VipUsername,
EffectiveDate,
AccountNoOldValue,
AccountNoNewValue
from
SageStaging.MASSMART.AuditCondensed
where
FieldName = 'Account Number'
) b
on
a.Auditfieldid = b.Auditfieldid and
a.CompanyRuleID = b.CompanyRuleID and
a.CompanyRule = b.CompanyRule and
a.VipUsername = b.VipUsername and
a.EffectiveDate = b.EffectiveDate
join
(
select
Auditfieldid,
CompanyRuleID,
CompanyRule,
VipUsername,
EffectiveDate,
AccountTypeOldValue,
AccountTypeNewValue
from
SageStaging.MASSMART.AuditCondensed
where
FieldName = 'Account Type'
) c
on
a.Auditfieldid = c.Auditfieldid and
a.CompanyRuleID = c.CompanyRuleID and
a.CompanyRule = c.CompanyRule and
a.VipUsername = c.VipUsername and
a.EffectiveDate = c.EffectiveDate
join
(
select
Auditfieldid,
CompanyRuleID,
CompanyRule,
VipUsername,
EffectiveDate,
BankOldValue,
BankNewValue
from
SageStaging.MASSMART.AuditCondensed
where
FieldName = 'Bank'
) d
on
a.Auditfieldid = d.Auditfieldid and
a.CompanyRuleID = d.CompanyRuleID and
a.CompanyRule = d.CompanyRule and
a.VipUsername = d.VipUsername and
a.EffectiveDate = d.EffectiveDate
join
(
select
Auditfieldid,
CompanyRuleID,
CompanyRule,
VipUsername,
EffectiveDate,
BranchOldValue,
BranchNewValue
from
SageStaging.MASSMART.AuditCondensed
where
FieldName = 'Bank Branch'
) e
on
a.Auditfieldid = e.Auditfieldid and
a.CompanyRuleID = e.CompanyRuleID and
a.CompanyRule = e.CompanyRule and
a.VipUsername = e.VipUsername and
a.EffectiveDate = e.EffectiveDate;
You have been given an appalling database design; I'm not surprised you find it difficult. The name suggests that it is condensed data. It isn't. It is actually a very wasteful structure.
I am concerned about the assertion that there are 5 rows for each employee. If some don't have all 5 rows you will have to do outer joins. You will need one reliable record type for each employee if this is the case.
From personal experience, whenever you build a string like that, concatenating a bunch of strings together, you should wrap each variable in an ISNULL check. One null variable, and the entire string will be null.
You should probably isolate the logic for creating the email body in a function. Here's a full example with sample DDL and DML statements for testing:
CREATE TABLE AuditCondensed (
[AuditFieldID] INT
,[CompanyRuleID] INT
,[CompanyRule] VARCHAR(10)
,[VipUserName] VARCHAR(10)
,[EffectiveDate] DATE
,[FieldName] VARCHAR(25)
,[SourceCode] VARCHAR(25)
,[Action] CHAR(1)
,[AccountNoOldValue] VARCHAR(25)
,[AccountNoNewValue] VARCHAR(25)
,[AccountTypeOldValue] VARCHAR(25)
,[AccountTypeNewValue] VARCHAR(25)
,[BankOldValue] VARCHAR(25)
,[BankNewValue] VARCHAR(25)
,[BranchOldValue] VARCHAR(25)
,[BranchNewValue] VARCHAR(25)
,[AccountHolderOldValue] VARCHAR(25)
,[AccountHolderNewValue] VARCHAR(25))
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Number', '1234 - John Doe', 'I', '12345', '1234567-123', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Type', '1234 - John Doe', 'I', NULL, NULL, NULL, 'Savings', NULL, NULL, NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Bank', '1234 - John Doe', 'I', NULL, NULL, NULL, NULL, 'Old Bank', 'New Bank', NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Branch', '1234 - John Doe', 'I', NULL, NULL, NULL, NULL, NULL, NULL, 'Branch 1', 'Branch 2', NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Holder', '1234 - John Doe', 'I', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '', 'John Doe')
CREATE FUNCTION dbo.fn_create_email_body(#SourceCode VARCHAR(25)) RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #MailSubject NVARCHAR(200) = ''
DECLARE #MessageBody NVARCHAR(MAX) = ''
DECLARE #EFFECTIVEDATE DATE
DECLARE #COMPANYRULE VARCHAR(10)
DECLARE #VIPUSERNAME VARCHAR(10)
DECLARE #ACTION CHAR(1)
DECLARE #ACCOUNTHOLDEROLDVALUE VARCHAR(25)
DECLARE #ACCOUNTHOLDERNEWVALUE VARCHAR(25)
DECLARE #ACCOUNTNOOLDVALUE VARCHAR(25)
DECLARE #ACCOUNTNONEWVALUE VARCHAR(25)
DECLARE #ACCOUNTTYPEOLDVALUE VARCHAR(25)
DECLARE #ACCOUNTTYPENEWVALUE VARCHAR(25)
DECLARE #BANKOLDVALUE VARCHAR(25)
DECLARE #BANKNEWVALUE VARCHAR(25)
DECLARE #BRANCHOLDVALUE VARCHAR(25)
DECLARE #BRANCHNEWVALUE VARCHAR(25)
SELECT TOP 1 #EFFECTIVEDATE = EffectiveDate, #COMPANYRULE = CompanyRule, #VIPUSERNAME = VipUserName, #ACTION = Action,
#ACCOUNTHOLDEROLDVALUE = (SELECT AccountHolderOldValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Holder'),
#ACCOUNTHOLDERNEWVALUE = (SELECT AccountHolderNewValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Holder'),
#ACCOUNTNOOLDVALUE = (SELECT AccountNoOldValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Number'),
#ACCOUNTNONEWVALUE = (SELECT AccountNoNewValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Number'),
#ACCOUNTTYPEOLDVALUE = (SELECT AccountTypeOldValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Type'),
#ACCOUNTTYPENEWVALUE = (SELECT AccountTypeNewValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Account Type'),
#BANKOLDVALUE = (SELECT BankOldValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Bank'),
#BANKNEWVALUE = (SELECT BankNewValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Bank'),
#BRANCHOLDVALUE = (SELECT BranchOldValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Branch'),
#BRANCHNEWVALUE = (SELECT BranchNewValue FROM AuditCondensed WHERE SourceCode = #SourceCode AND FieldName = 'Branch')
FROM AuditCondensed
WHERE SourceCode = #SourceCode
SET #MessageBody = '<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title></title>
</head>
<body>
<br>
The following bank details have been changed:
<br>
<br>
Date Changed: ' + ISNULL(FORMAT(#EFFECTIVEDATE, 'M/d/yyyy'), '') + '<br>' +
' Company: ' + ISNULL(#COMPANYRULE, '') + '<br>' +
' Username: ' + ISNULL(#VIPUSERNAME, '') + '<br>' +
' Employee Details: ' + ISNULL(#SOURCECODE, '') + '<br>' +
' Action: ' + ISNULL(#ACTION, '') + '<br>' +
' Account Holder: ' + ' Old Value: ' + ISNULL(#ACCOUNTHOLDEROLDVALUE, '') + ' New Value: ' + ISNULL(#ACCOUNTHOLDERNEWVALUE, '') + '<br>' +
' Account Number: ' + ' Old Value: ' + ISNULL(#ACCOUNTNOOLDVALUE, '') + ' New Value: ' + ISNULL(#ACCOUNTNONEWVALUE, '') + '<br>' +
' Account Type: ' + ' Old Value: ' + ISNULL(#ACCOUNTTYPEOLDVALUE, '') + ' New Value: ' + ISNULL(#ACCOUNTTYPENEWVALUE, '') + '<br>' +
' Bank: ' + ' Old Value: ' + ISNULL(#BANKOLDVALUE, '') + ' New Value: ' + ISNULL(#BANKNEWVALUE, '') + '<br>' +
' Bank Branch: ' + ' Old Value: ' + ISNULL(#BRANCHOLDVALUE, '') + ' New Value: ' + ISNULL(#BRANCHNEWVALUE, '') + '<br>' +
'<br>
<br>
<b>
Please do not respond to this email. If you have any questions regarding this email, please
contact your payroll administrator <br>
<br>
<br>
</body>'
RETURN #MessageBody
END
GO
SELECT dbo.fn_create_email_body('1234 - John Doe')
Note the query in the function that sets all the variable values. It uses TOP to set the values for all the constant variables, and subqueries to conditionally set the variables that are dependent on the FieldName. If you use this, you'll need to make sure the data types of the variables (and lengths) match your database.
Perhaps another approach dbFiddle
Example
-- Just creating a DUMMY dataset --
-----------------------------------
Declare #YourTable table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #YourTable values
(1,1,'John','Smith','johnsmith.#email.com'),
(2,0,'Jane','Doe','janedoe.#email.com')
-- Here we have our Pattern/Template --
---------------------------------------
Declare #Pattern varchar(max) = '
Dear [[First_Name]] [[Last_Name]]
Please confirm your email address <b>[[EMail]]</b>
Thank You
'
-- The actual query --
----------------------
Select A.ID
,Formatted = [dbo].[svf-Str-Tokenize]((Select A.* for XML Raw),#Pattern)
From #YourTable A
Returns
ID Formated
1 Dear John Smith
Please confirm your email address <b>johnsmith.#email.com</b>
Thank You
2 Dear Jane Doe
Please confirm your email address <b>janedoe.#email.com</b>
Thank You
The UDF if Interested
CREATE FUNCTION [dbo].[svf-Str-Tokenize](#XML xml,#Template varchar(max))
Returns varchar(max)
Begin
Select #Template = Replace(#Template,Item,Value)
From (
Select Item = '[['+attr.value('local-name(.)','varchar(100)')+']]'
,Value = attr.value('.','varchar(max)')
From #XML.nodes('/row') as xn(n)
Cross Apply xn.n.nodes('./#*') AS xa(attr)
Union All
Select Item = left(Item,charindex(']]',Item)+1)
,Value = ' '
From (
Select Item = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(replace(#Template,'[[','||[['),'||','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) P
Where charindex('[[',Item)>0 and charindex(']]',Item)>0
) A
Return ltrim(rtrim(replace(replace(replace(#Template,' ','><'),'<>',''),'><',' ')))
End

SQL server, concat nvarchar when some are null

Probably a question of null values...
I would like to do just like in C# :
string s3 = s2 + ' ' + s1;
witch could be read like :
'hello world' = 'hello' + ' ' + 'world
But in SQL, some of my NVARCHAR(1) are null, so it sometimes look like :
null = 'hello + ' ' + null
And in this case i would rather have :
'hello ' = 'hello' + ' ' + null
I don't see, is there a simple way to do that ?
Use COALESCE() or ISNULL():
SELECT COALESCE(S2, '') + ' ' + COALESCE(S1, '')
Or:
SELECT ISNULL(S2, '') + ' ' + ISNULL(S1, '')
You can also use IIF() function or else CASE Statement
SELECT IIF(s2 IS NULL, '', s2) + ' ' + IIF(s1 IS NULL, '', s1)

SQL Server: help with a simple stored procedure?

I'm trying to create a simple stored procedure which I can use to write data to a log table. I'm a noob in stored procedures, so what I'm missing here? I get an error saying:
Msg 201, Level 16, State 4, Procedure toLog, Line 0
Procedure or function 'toLog' expects parameter '#messageTime', which was not supplied.
How to modify this code to get this work?
USE <database>
GO
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'logTable')
DROP TABLE dbo.logTable
GO
CREATE TABLE dbo.logTable (
messageTime DATETIME NULL,
etlJobName NVARCHAR(40) NULL,
whereTo VARCHAR(10) NOT NULL,
messag VARCHAR(255) NULL
)
/*************** procedure ************/
--DROP PROC dbo.toLog
CREATE PROCEDURE dbo.toLog
#messageTime DATETIME,
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
SET #messageTime = GETDATE()
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (#messageTime, #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, GETDATE(), 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END
GO
--execution
EXEC dbo.toLog #whereTo = 'log'
It's because your toLog sproc is expecting you to supply the #messageTime parameter, which you haven't done, and it doesn't have a default value like the other parameters.
As you set the #messageTime always to GETDATE() inside the sproc, it looks like you just want to scrap that parameter:
CREATE PROCEDURE dbo.toLog
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (GETDATE(), #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, GETDATE(), 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END
Or, if you do want to be able to pass in a datetime yourself:
CREATE PROCEDURE dbo.toLog
#messageTime DATETIME = null,
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
IF (#messagetime IS NULL) SET #messagetime = GETDATE()
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (#messageTime, #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, #MessageTime, 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END
When You are creating the stored procedure with parameters, At any cause we need to pass the parameter values, when executing stored procedure.
Example 1:
EXEC dbo.toLog '','','',''
In the above line when you are executing the stored procedure , it will not thrown any errors. because passed the Parameters values are a NULL.
Example 2:
EXEC dbo.toLog '','','log',''
In the above line when you are executing the stored procedure , it will not thrown any errors, data will be Logged in your table. Based on the Stored procedure inside script logic

2147217833 String or binary data would be truncated

Hi Have an error occuring when I try to update a record via stored procedure.
The error I get is 2147217833 String or binary data would be truncated.
I've done a length on each of the fields that I'm inserted and they should be fitting comfortably in to the the database fields - i.e. the length isn't greater that the column specifications.
Completely baffled at the moment - any other reasons why this error might occur?
Thanks,
Set objReturnParam = objComm.CreateParameter("Return",adInteger,adParamReturnValue)
Set objRiskIDParam = objComm.CreateParameter("#riskID",adBigInt,adParamInput)
Set objControlsDescriptionParam = objComm.CreateParameter("#ControlsDescription",adVarChar,adParamInput,5000)
Set objTreatmentParam = objComm.CreateParameter("#Treatment",adVarChar,adParamInput,5000)
Set objControlsParam = objComm.CreateParameter("#Controls",adVarChar,adParamInput,10)
Set objPriorityParam = objComm.CreateParameter("#Priority",adVarChar,adParamInput,6)
Set objProbabilityParam = objComm.CreateParameter("#Probability",adVarChar,adParamInput,6)
Set objImpactParam = objComm.CreateParameter("#Impact",adVarChar,adParamInput,6)
Set objScoreParam = objComm.CreateParameter("#Score",adInteger,adParamInput)
Set objReviewTimeframeParam = objComm.CreateParameter("#ReviewTimeframe",adVarChar,adParamInput,6)
Set objReviewDateParam = objComm.CreateParameter("#ReviewDate",adDate,adParamInput)
Set objDateReviewedParam = objComm.CreateParameter("#DateReviewed",adDate,adParamInput)
Set objReviewerIDParam = objComm.CreateParameter("#ReviewerID",adInteger,adParamInput)
objComm.Parameters("#riskID") = lRiskID
objComm.Parameters("#ControlsDescription") = strControlsDescription
objComm.Parameters("#Treatment") = strTreatment
objComm.Parameters("#Controls") = strControls
objComm.Parameters("#Priority") = strPriority
objComm.Parameters("#Probability") = strProbability
objComm.Parameters("#Impact") = strImpact
objComm.Parameters("#Score") = iScore
objComm.Parameters("#ReviewTimeframe") = strReviewTimeframe
objComm.Parameters("#ReviewDate") = cStr(Year(dReviewDate)) + "-" + cStr(Month(dReviewDate)) + "-" + cStr(Day(dReviewDate)) + " 00:00:00"
objComm.Parameters("#DateReviewed") = cStr(Year(Date)) + "-" + cStr(Month(Date)) + "-" + cStr(Day(Date)) + " 00:00:00"
objComm.Parameters("#ReviewerID") = Cstr(Session("UserID"))
when I output each of the variables that I'm trying to update, the length of each is:
lRiskID: 2
strControlsDescription: 6
strTreatment: 6
strControls: 4
strPriority: 0
strProbability: 1
strImpact: 1
iScore: 1
strReviewTimeframe: 0
Reviewdate19
dateReviewed19
reviewerid2
[ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[CONTROLS_DESCRIPTION] [varchar](5000) COLLATE Latin1_General_CI_AS NOT NULL,
[TREATMENT] [varchar](5000) COLLATE Latin1_General_CI_AS NOT NULL,
[PRIORITY] [varchar](6) COLLATE Latin1_General_CI_AS NOT NULL,
[PROBABILITY] [varchar](6) COLLATE Latin1_General_CI_AS NOT NULL,
[IMPACT] [varchar](6) COLLATE Latin1_General_CI_AS NOT NULL,
[SCORE] [tinyint] NOT NULL,
[REVIEW_TIMEFRAME] [varchar](6) COLLATE Latin1_General_CI_AS NOT NULL,
[PROPOSED_REVIEW_DATE] [datetime] NOT NULL,
[DATE_REVIEWED] [datetime] NULL,
[REVIEWER_ID] [int] NULL,
Without schema and code, it's be hard.
Random thoughts:
Are you concatenating, or using CAST/varchar without a length?
Do you have trailing spaces (for example, LEN ignores trailing spaces)
Or is there an audit trigger?
Edit, after code added
Where does #Controls go? There is no column...
To me, this implies the truncate error is not for this table
Your parameter declarations do not all match the data types of your table. You're using adBigInt for a numeric (use adNumeric), adInteger for a tinyint (use adTinyInt).
It looks like you're in VB6, and in VB6 the adDate datatype was used for Access. For updating a SQL Server DB you need to use adDBTimeStamp as the parameter datatype instead.
http://www.devguru.com/Technologies/ado/quickref/command_createparameter.html