Error when executing query with variables in sp_send_dbmail - tsql

I am trying to send emails individually to a list of recipients. I am receiving the error:
Msg 22050, Level 16, State 1, Line 0
Error formatting query, probably invalid parameters
Msg 14661, Level 16, State 1, Procedure sp_send_dbmail, Line 478
Query execution failed: Msg 4104, Level 16, State 1, Server xxxxxx, Line 1
The multi-part identifier "email#example.com" could not be bound.
Here is a simplified version of my code, asssuming table1 is a valid existing table and name and email are existing columns.
declare #current_mailaddress varchar(50), #query varchar(1000)
set #current_mailaddress = 'email#example.com'
set #query = 'select distinct name, email from table1
where email = ' + #current_email
exec msdb.dbo.sp_send_dbmail
#recipients = #current_email,
#subject = 'test',
#query = #query
So according to the error, the formatting (of presumably the #query) is wrong. I can't figure it out. Any ideas?

You need to put the value of #current_email in quotes:
'SELECT ... WHERE email = ''' + #current_email + ''''
To see why, consider what your query currently looks like without it:
SELECT ... WHERE email = email#example.com
Any time you work with dynamic SQL, it's a good idea to PRINT the variable for debugging if you get a strange error; it's usually the case that the SQL string you've built is not the one you're expecting. I suggested an easy way to manage debugging code in another, unrelated answer.

Related

How to fetch doctype eg: address or tax rule

I want to fetch the doctype. How do I do this? I want to add a separate column which will give doctype such as sales order, purchase order etc. The first line gives me error what query should be fired. Please help I am new to ERP Next.
SELECT
AD.ref_doctype AS “Doctype:Link/User:120”,
AD.name AS “Doc#:Link/Doctype:120”,
AD.owner AS “Created By:Link/User:120”,
AD.modified AS “Modified On:Date:120”
FROM tabAddress AS AD
WHERE
DATEDIFF(now(),AD.modified) BETWEEN 1 AND 30
UNION ALL
SELECT
TR.name AS “Doc#:Link/Doctype:120”,
TR.owner AS “Created By:Link/User:120”,
TR.modified AS “Modified On:Date:120”
FROM tabTax Rule AS TR
WHERE
DATEDIFF(now(),TR.modified) BETWEEN 1 AND 30
UNION ALL
SELECT
IT.name AS “Doc#:Link/Doctype:120”,
IT.owner AS “Created By:Link/User:120”,
IT.modified AS “Modified On:Date:120”
FROM tabItem AS IT
WHERE
DATEDIFF(now(),IT.modified) BETWEEN 1 AND 30
It isn't completely clear to me what you mean by docType field.
Are you wanting a result like this?
Doctype:Link/User:120|Doc#:Link/Doctype:120|Created By:Link/User:120|Modified On:Date:120|
---------------------|---------------------|------------------------|--------------------|
Email Account |Jobs |Administrator | 2019-12-04 06:07:55|
Email Account |Notifications |Administrator | 2019-12-01 05:25:53|
Email Account |Replies |Administrator | 2019-12-01 05:25:53|
Email Account |Sales |Administrator | 2019-12-04 06:07:55|
Email Account |Support |Administrator | 2019-12-04 06:07:55|
Here's the select :
set #docType = "Email Account";
SELECT
#tabDocType AS `Doctype:Link/User:120`,
AD.name AS `Doc#:Link/Doctype:120`,
AD.owner AS `Created By:Link/User:120`,
AD.modified AS `Modified On:Date:120`
FROM `tabEmail Account` AS AD
Note the backticks on the field aliases! All these have different meanings in SQL:
"
'
`
The last one, backtick, is used to refer to database entities. You were trying to use “Doctype:Link/User:120” with double quotes, which declare plain text. Using backtick converts the alias into a db entity which can be referred to from elsewhere.
MariaDb doesn't allow the use of variables as table names directly, but you can do it using prepared statements, like this:
set #docType = "Email Account";
set #tabDocType = CONCAT('tab', #docType);
SET #sql_text = concat('
SELECT
"', #docType, '" AS `Doctype:Link/User:120`
, AD.name AS `Doc#:Link/Doctype:120`
, AD.owner AS `Created By:Link/User:120`
, AD.modified AS `Modified On:Date:120`
FROM `', #tabDocType, '` as AD;
');
PREPARE stmt FROM #sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
The table name is now also specified by a variable, created from concatenation of 'tab' with the docType declared before.
You get the same result as above but -- you avoid accidentally changing the table name in one place but not in the other when editing some time in the future.
to fetch doctype name you have to give the linked doctype name, For example,
select
IT.name as "IT No:Link/IT:120"

How to quote column names on the commandline of fbexport

As the title says, how am I going to deal with a column name in FBExport that look like a keyword?
this is how my statement looks like:
-Q "SELECT a.ID, a.USERID, a.`WHEN`, a.INOUT FROM ATTENDANT a"
then I get this error:
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 26
WHEN
When I use
"WHEN"
Error: Switches must begin with -
tried 'When'
-Q "SELECT a.ID, a.USERID, a.'WHEN', a.INOUT FROM ATTENDANT a;"
SQL Message : -104
Invalid token
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 26
'WHEN'
Error: Switches must begin with -
What are the correct escape characters?
For dialect 3 database, Firebird allows quoting object names using double quotes ("<objectname>"). Be aware that quoting object names makes them case sensitive, so "WHEN" is not the same as "when". If your database is dialect 1 then this is not possible, and you should first convert your database to dialect 3.
However the problem this is a command line option, meaning that
-Q "SELECT a.ID, a.USERID, a."WHEN", a.INOUT FROM ATTENDANT a"
Is split by your shell to the arguments:
-Q
SELECT a.ID, a.USERID, a.
WHEN
, a.INOUT FROM ATTENDANT a
While you want:
-Q
SELECT a.ID, a.USERID, a."WHEN", a.INOUT FROM ATTENDANT a
To achieve that, you need to escape the double quote inside the second argument, so:
-Q "SELECT a.ID, a.USERID, a.\"WHEN\", a.INOUT FROM ATTENDANT a"
or - as indicated by a_horse_with_no_name in the comments - wrap the argument in single quotes:
-Q 'SELECT a.ID, a.USERID, a."WHEN", a.INOUT FROM ATTENDANT a'
This doesn't really have to do with Firebird or FBExport, but is a result of how your shell (eg bash) parses commandline arguments.
It looks like someone else is dealing with the external access to the Firebird database from Safescan TimeAttenedant
It was a little bit stupid from Safescan to name a column WHEN because this is a keyword in Firebird.
In the context of an insert statement, I have no success with a column list like:
insert into attendant (ID, USERID, DEVICEID, WHEN, INOUT, VERIFYMODE, WORKCODE) values (1092, 1, 1, '28.08.2017 08:00', 0, 4, 3);
"WHEN", \"WHEN\", \'WHEN\', ... no success
Remedy - Insert all data without column list, ex:
insert into attendant values (1034, 2, 1, '28.08.2017 08:00', 0, 4, null, null, null, null, null, 3);
Query is much easier: select * from attendant;

Dynamic SQL Error with REPLACE Statement

I am trying to create a script that builds a SQL statement dynamically and then executes it.
Here is the string that is built & stored in #strSQL (verified by using PRINT)
UPDATE DNN_RSM_Exams
SET ScoringDates = REPLACE(ScoringDates, '/2015', '/2016')
WHERE SchoolYear = 2015
It executes the variable as follows:
EXECUTE (#strSQL)
However I get the following error:
Conversion failed when converting the nvarchar value 'UPDATE DNN_RSM_Exams SET ScoringDates = REPLACE(ScoringDates, '/' to data type int.
It seems to terminate the EXECUTE when it hits the first forward-slash (/). I tried escaping it using a double slash (//), an open bracket ([), and a backslash (\). None if it worked.
Can anyone help me please?
UPDATE #01: 8/17/15
Sorry if I didn't give enough information initially...
ScoringDates is an NVARCHAR(MAX) field.
The Code that builds the SQL Statement is:
SET #strSQL = 'UPDATE ' + #strTableName +
' SET ScoringDates = REPLACE(ScoringDates, ''/' + LTRIM(RTRIM(STR(#intSchoolYear_CopyFrom + 1))) + ''', ''/' + LTRIM(RTRIM(STR(#intSchoolYear_CopyFrom + 2))) + ''')' +
' WHERE SchoolYear = ' + LTRIM(RTRIM(STR(#intSchoolYear_CopyTo)))
ScoringDates is a string based field that holds data in an INI-like formatted string. I want to change the year portion of ANY date found in the string, but I want to avoid accidental changes of any other numbers that may match. So I am specifically looking to replace "/YYYY" with a different "YYYY" value. The "/" preceding the year value is to ensure that what is being preplaced is the YEAR and not another numeric value within the string.
UPDATE #02: 8/18/15
So I am completely flabbergasted...after banging my head on this script for hours yesterday, I went home defeated. Come in today, start up my PC and run the script again so I can see the error message again...and it worked!
I've never come across this with SQL Management Studio, but it is possible that SQL Management Studio somehow lost it's marbles yesterday and needed a reboot? I thought the SQL was process by the server directly. Could it be that some is processed by the studio first before handing it off to the server and if the studio had "issues" then it would cause strange errors?
In any case, thank you so much guys for your input, I am sorry that it was a wheel spinner. It never occurred to me that a reboot would fix my issue, I just assumed my code was wrong.
You want to replace '/ with ''
So your set statement will be something like...
SET #strSQL = 'UPDATE DNN_RSM_Exams
SET ScoringDates = REPLACE(ScoringDates, ''2015'', ''2016'')
WHERE SchoolYear = 2015'
EDIT:
How is your code different than this below? (I will edit this again and clean it up after. Code just won't fit into comments)
DECLARE #TableName TABLE (ScoringDates VARCHAR(100), SchoolYear INT)
DECLARE #strTableName VARCHAR(MAX)
DECLARE #intSchoolYear_CopyFrom VARCHAR(MAX)
DECLARE #intSchoolYear_CopyTo VARCHAR(MAX)
SET #strTableName = '#TableName'
SET #intSchoolYear_CopyFrom = '2009'
SET #intSchoolYear_CopyTo = '2010'
DECLARE #strSQL VARCHAR(MAX)
SET #strSQL = 'DECLARE #TableName TABLE (ScoringDates VARCHAR(100), SchoolYear INT); UPDATE ' + #strTableName +
' SET ScoringDates = REPLACE(ScoringDates, ''/' + LTRIM(RTRIM(STR(#intSchoolYear_CopyFrom + 1))) + ''', ''/' + LTRIM(RTRIM(STR(#intSchoolYear_CopyFrom + 2))) + ''')' +
' WHERE SchoolYear = ' + LTRIM(RTRIM(STR(#intSchoolYear_CopyTo)))
PRINT #strSQL
EXECUTE (#strSQL)

Prevent sql injection, Activerecord #where, with multiple AND/OR clause

I am fairly new to rails. I have a rails Model 'Message' with: 'belongs_to :sender' and 'belongs_to :receiver' relations.
I am trying to create a message thread between two users: 'current_user' and 'params'.
In the show controller action of the MessagesController, I want to use the equivalent of this sql query:
Message.find_by_sql(
"SELECT *
FROM messages
WHERE
(sender_id = #{current_user.id} OR sender_id = #{params[:id]})
AND
(receiver_id = #{current_user.id} OR receiver_id = #{params[:id]});"
)
If I where looking for one Message I would use this Activerecord queryto prevent SQL injection:
Message.where('sender_id = ? OR receiver_id = ?', current_user.id, current_user.id).find(params[:id])
My current query is:
Message.where(sender_id: [current_user.id, params[:id]], receiver_id: [current_user.id, params[:id]])
Is this query currently guarded against SQL injection?
it's safe. the final query would be something like sender_id IN (1, 2) AND receiver_id IN (3, 4) and all integer values are sanitized. You can simply run tests:
Message.where(sender_id: [current_user.id, "' is dangerous"], receiver_id: [current_user.id, params[:id]])
and see raw SQL output in console. illegal integers should be converted to 0.

Nested SELECT statement in a CASE expression

Greetings,
Here is my problem.
I need to get data from multiple rows and return them as a single result in a larger query.
I already posted a similar question here.
Return multiple values in one column within a main query but I suspect my lack of SQL knowledge made the question too vague because the answers did not work.
I am using Microsoft SQL 2005.
Here is what I have.
Multiple tables with CaseID as the PK, CaseID is unique.
One table (tblKIN) with CaseID and ItemNum(AutoInc) as the combined PK.
Because each person in the database will likely have more than one relative.
If I run the following, in a SQL query window, it works.
DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = 'xxx' and Address = 'yyy'
ORDER BY KINRel
SELECT #KINList
This will return the relation of all people who live at the same address. the results look like this...
Father, Niece, Sister, Son
Now, the problem for me is how do I add that to my main query?
Shortened to relevant information, the main query looks like this.
SELECT DISTINCT
c.CaseID,
c.Name,
c.Address,
Relatives=CASE WHEN exists(select k.CaseID from tblKIN k where c.CaseID = k.CaseID)
THEN DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = 'xxx' and Address = 'yyy'
ORDER BY KINRel
SELECT #KINList
ELSE ''
END
FROM tblCase c
ORDER BY c.CaseID
The errors I receive are.
Server: Msg 156, Level 15, State 1, Line 13
Incorrect syntax near the keyword 'DECLARE'.
Server: Msg 156, Level 15, State 1, Line 18
Incorrect syntax near the keyword 'ELSE'.
I tried nesting inside parenthesis from the DECLARE to the end of the SELECT #KINList.
I tried adding a BEGIN and END to the THEN section of the CASE statement.
Neither worked.
The source table data looks something like this. (periods added for readability)
tblCase
CaseID Name Address
10-001 Jim......100 Main St.
10-002 Tom....150 Elm St.
10-003 Abe.....200 1st St.
tblKIN
CaseID ItemNum Name Relation Address
10-001 00001 Steve...Son........100 Main St.
10-002 00002 James..Father....150 Elm St.
10-002 00003 Betty....Niece......150 Elm St.
10-002 00004 Greta...Sister.....150 Elm St.
10-002 00005 Davey..Son........150 Elm St.
10-003 00006 Edgar...Brother...200 1st St.
If I run the query for CaseID = 10-002, it needs to return the following.
CaseID Name Address.......Relatives
10-002 Tom...150 Elm St. ..Father, Niece, Sister, Son
I am sure this is probably a simple fix, but I just don't know how to do it.
Thank you for your time, and I apologize for the length of the question, but I wanted to be clear.
Thanks !!!
When I did something similar I had to create a scalar function to do the coalesce that returns the varchar result. Then just call it in the select.
CREATE FUNCTION GetRelatives
(
#CaseID varchar(10)
)
RETURNS varchar(1000)
AS
BEGIN
DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = #CaseID
ORDER BY KINRel
RETURN #KINList
END
Then your select
SELECT DISTINCT
c.CaseID,
c.Name,
c.Address,
database.dbo.GetRelatives(c.CaseID) AS Relatives
FROM tblCase c
ORDER BY c.CaseID
You can create a FUNCTION which takes in the caseID as the arguement and returns true or false.
Since you are calling the nested query multiple times, its definitely a performance hit. A better solution is to execute the query and store the results in a temporary table.
Then pass this temporary table and the caseID to the FUNCTION and check for containment.