Boolean expressions in SQL Server jobs - sql-server

I have inherited a SQL Server "job" that does several things. There are two "steps" and each has multiple statements one is:
UPDATE Person
SET Person.LastName = P.LastName,
Person.FirstName = P.FirstName,
Person.MiddleName = P.MiddleName,
Person.EmailAddress = P.EmailAddress,
Person.StartDate = P.StartDate,
Person.EndDate = P.EndDate
FROM OtherDB.dbo.Person Person
INNER JOIN FirstDB.dbo.Persons AS P ON P.PersonId = Person.PersonId
WHERE Person.LastName != P.LastName
OR Person.FirstName != P.FirstName
OR Person.MiddleName != P.MiddleName
OR Person.EmailAddress != P.EmailAddress
OR Person.StartDate != P.StartDate
OR Person.EndDate != P.EndDate;
It is updating "person" data from FirstDB into OtherDB. The PersonId columns are bigints and are not null. The various "date" columns are of type datetime and could be NULL. The other columns are all varchar and could be NULL.
What I have learned is that, in the where clause, if NULL appears on either or both sides of the boolean operator the result is undefined. Basically, NULL can neither equal nor not-equal NULL. It appears that the same applies to NULL and any other non-null value.
So I thought to try:
UPDATE Person
SET Person.LastName = P.LastName,
Person.FirstName = P.FirstName,
Person.MiddleName = P.MiddleName,
Person.EmailAddress = P.EmailAddress,
Person.StartDate = P.StartDate,
Person.EndDate = P.EndDate
FROM OtherDB.dbo.Person Person
INNER JOIN FirstDB.dbo.Persons AS P ON P.PersonId = Person.PersonId
WHERE ISNULL(Person.LastName, '') != ISNULL(P.LastName, '')
OR ISNULL(Person.FirstName, '') != ISNULL(P.FirstName, '')
OR ISNULL(Person.MiddleName, '') != ISNULL(P.MiddleName, '')
OR ISNULL(Person.EmailAddress, '') != ISNULL(P.EmailAddress, '')
OR ISNULL(Person.StartDate, '') != ISNULL(P.StartDate, '')
OR ISNULL(Person.EndDate, '') != ISNULL(P.EndDate, '');
This works in a regular query window but fails in the job. The error is:
An expression of non-boolean type specified in a context where a condition is expected, near 'OR'. [SQLSTATE 42000] (Error 4145). The step failed.
I am not seeing a problem. What am I missing?
Edit
As requested, for others in this situation: I edited this job by using SQL Server Management Studio. I opened a connection to my target DB then opened the "SQL Server Agent" drop-down under the connection. I opened "Jobs" and found the job i was looking for. I right-clicked on the job name and selected "Script Job As" -> "Drop and Create to" -> "New Query Window". From there I copied the relevant sections to new query windows where I modified and tested them as necessary. I then just copied and pasted the working sections back into the job window above -- COMPLETELY forgetting to double up the single quotes where necessary.

How did you add the step to the job? I wonder if a script you used escaped all of your double apostrophes and it is now trying to evaluate
WHERE ISNULL(Person.LastName, ') != ISNULL(P.LastName, ')
------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^
That's "valid enough" syntax. The highlighted portion is a simple string literal, not an empty string and a comparison to another expression.

Related

EF6 query that behaves strangely using contains

I have an EF6 SQL Server query that behaves strangely when it is supplied with a List<int> of IDs to use. If bookGenieCategory = a value it works. If selectedAges is empty (count = 0) all is well. If the selectedAges contains values that exist in the ProductCategory.CategoryId column, the contains fails and NO rows are returned.
Note: AllocationCandidates is a view, which works properly on its own.
CREATE VIEW dbo.AllocationCandidate
AS
SELECT
p.ProductID, p.SKU as ISBN, p.Name as Title,
pv.MSRP, pv.Price, pv.VariantID, pv.Inventory,
ISNULL(plt.DateLastTouched, GETDATE()) AS DateLastTouched,
JSON_VALUE(p.MiscText, '$.AgeId') AS AgeId,
JSON_VALUE(p.MiscText, '$.AgeName') AS AgeName
FROM
dbo.Product AS p WITH (NOLOCK)
INNER JOIN
dbo.ProductVariant AS pv WITH (NOLOCK) ON pv.ProductID = p.ProductID
LEFT OUTER JOIN
dbo.KBOProductLastTouched AS plt WITH (NOLOCK) ON plt.ProductID = p.ProductID
WHERE
(ISJSON(p.MiscText) = 1)
AND (p.Deleted = 0)
AND (p.Published = 1)
AND (pv.IsDefault = 1)
GO
Do I have a typo here or a misplaced parenthesis in the following query?
var returnList = (from ac in _db.AllocationCandidates
join pc in _db.ProductCategories on ac.ProductID equals pc.ProductID
where (bookGenieCategory == 0
|| bookGenieCategory == pc.CategoryID)
&&
(selectedAges.Count == 0 ||
selectedAges.Contains(pc.CategoryID))
orderby ac.AgeId, ac.DateLastTouched descending
select ac).ToList();
Firstly, I would recommend extracting the conditionals outside of the Linq expression. If you only want to filter data if a value is provided, move the condition check outside of the Linq rather than embedding it inside the condition. This is generally easier to do with the Fluent Linq than Linq QL. You should also aim to leverage navigation properties for relationships between entities. This way an AllocationCandidate should have a collection of ProductCategories:
var query = _db.AllocationCandidates.AsQueryable();
if (bookGenieCategory != 0)
query = query.Where(x => x.ProductCategories.Any(c => c.CategoryID == bookGenieCategory);
The next question is what does the selectedAges contains? There is an Age ID on the AllocationCandidate, but your original query is checking against the ProductCategory.CategoryId??
If the check should be against the AllocationCandidate.AgeId:
if (selectedAges.Any())
query = query.Where(x => selectedAges.Contains(x.AgeID));
If the check is as you wrote it against the ProductCategory.CategoryId:
if (selectedAges.Any())
query = query.Where(x => x.ProductCategories.Any(c => selectedAges.Contains(c.AgeID)));
Then add your order by and get your results:
var results = query.OrderBy(x => x.AgeId)
.ThenByDescending(x => x.DateLastTouched);
.ToList();

sp_send_dbmail Error Formatting Query

I have a SQL agent job that was working, but after adding a new left join to the dbmail query it's failing. The error is one I've seen all over that few people seem to have an answer for:
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 517
Query execution failed: Msg 105, Level 15, State 1, Server SQLSRV, Line 34
The message after Query Execution Failed tends to change and pick locations in the middle of words as the false culprit.
The query is as follows:
#Query = 'set nocount on
USE [Epicor10]
select
case when VoidOrder = 0 then "Not Void" else "Voided" end as ' + #Column1Name + ',
case when Approve = 0 then "NA" else "A" end as Approved,
case when poheader.Confirmed = 0 then "UC" else "C" end as Confirmed,
POHeader.PONum,
podetail.POLine,
pr.PORelNum,
TG.GLAccount,
convert(nvarchar,REPLACE(REPLACE(REPLACE(REPLACE( podetail.PartNum, CHAR(13), ""), CHAR(10), " "), CHAR(9), " "), ",", " ")) PartNum,
convert(nvarchar,REPLACE(REPLACE(REPLACE(REPLACE( podetail.LineDesc, CHAR(13), ""), CHAR(10), " "), CHAR(9), " "), ",", " ")) LineDesc,
OrderQty,
ISNULL(CONVERT(nVarChar(max), pr.DueDate, 121), NULL) RelDueDate,
ISNULL(CONVERT(nVarChar(max), PODetail.DueDate, 121), NULL) LineDueDate,
pr.ReceivedQty,
pr.RelQty,
(pr.RelQty - pr.ReceivedQty) BalanceDue,
EntryPerson,
ShipName,
BuyerID,
POHeader.VendorNum,
Vendor.VendorID,
convert(nvarchar(max),REPLACE(REPLACE(REPLACE(REPLACE(Vendor.Name, CHAR(13), ""), CHAR(10), " "), CHAR(9), " "), ",", "")) Name,
REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(CONVERT(nVarChar(max),ApprovedDate, 121), NULL), CHAR(13), ""), CHAR(10), " "), CHAR(9), " "), ",", "") LineApprovedDate,
ISNULL(CONVERT(nVarChar(max),OrderDate, 121), NULL) OrderDate,
convert(nvarchar,REPLACE(REPLACE(REPLACE(case when ApprovedBy = "username" then "usersname" else ApprovedBy End, CHAR(13), ""), CHAR(10), " "), CHAR(9), " ")) ApprovedBy
from [Epicor10].[Erp].[POHeader]
inner join [Epicor10].[Erp].Vendor on POHeader.VendorNum = Vendor.VendorNum
left join [Epicor10].[Erp].PODetail on poheader.company = podetail.company and poheader.PONum = podetail.PONUM
left join [Epicor10].[Erp].PORel pr on PODetail.Company = pr.company and PODetail.ponum = pr.PONum and PODetail.poline = pr.POLine
left join [Epicor10].[Erp].TranGLC TG on TG.Key1 = pr.PONum and TG.Key2 = pr.POLine and TG.Key3 = pr.PORelNum and TG.RelatedToFile = "PORel"
where POHeader.OpenOrder = 1 and OrderDate >= "2016-7-1" and OpenLine = 1 and VoidLine = 0 and VoidRelease = 0 and OpenRelease = 1
order by PONum, POLine, PORelNum'
Now this was working and sending fine until I was asked to add the GLAccount column, the last 'Left Join' on TranGLC is the trigger for the issue. If I remove that join again, it works, but I can't figure out what the problem with that is.
I've checked permissions on the agent (though I can't imagine why that table would've made a difference), I've done many redundant things to make sure its pointing to the database and schema. I've copied the query and run it standalone in another window and it works fine. Nothing I've found online has been helpful in pinpointing the problem.
UPDATE FOR COMMENTS:
Can I send it without the query?: Yes, I can even send the email with the query until I add the left join to TranGLC.
Permissions issue?: I also saw that a lot online as the usual cause, and that would make sense here. It doesn't seem to be the case though. No special permissions on this table that I can see. Its setup like the rest of the tables in the database>schema
Job Agent User: So here is where I'm a bit confused on the setup/relationship of everything. I'm running the sp under a Profile, which is set up under Management>Database Mail using Basic Authentication with an email we have for our domain. This email is actually the email for a domain user we have. I could try setting it to Windows Auth for the active user (me, since I'm an admin).
What I'm unclear about is how that works within SSAgent, most of what I've seen says to set up database mail under SSAgent>Properties>Alert System (Enable Mail profile is NOT checked here for us) but I'm unclear about the relationship. I feel like that's for something else entirely and shouldn't matter here.
From the looks online, everything points to some sort of permission issue somewhere in the process.
Questions to check would be: Are you able to send the email manually i.e. run the same exact job manually, not the query? Does that table or column have any special permissions? What happens if you change the user that the job agent runs as?

How to correctly set expression Query.CommandText in SSRS?

In my SSRS report builder I have an expression set for one of my dataset (name is dsTagAttributes). The query type is text.
This is the query expression
="select m.TagName, ta.descriptor, t.[State] from MasterTags m inner join TagAttributesClassic ta on m.ID = ta.TagID inner join TagStates t on t.ID = m.StateID where m.PIServerID = #ServerID and t.[State] = #State and m.MetaData1 = #Station " & Parameters!AndOr.Value & "m.MetaData2 = #Device"
The above query expression has a parameter which is concatenated in the select statement.
The parameter #AndOr data type is text, has a default value of "or", and parameter visibility is set to hidden (screen shot below). I have set this parameter because it will be used to dynamically change the dataset result from or to and during the report runtime.
But when I run the report, an exception is thrown saying,
What could go wrong in my query command text?
Any help is greatly appreciated.
You can run Profiler against Data Source to see the query.
I assume the problem is that you miss "'" before and after each varchar value (#State, #Station).
I wouldn't use that way to use OrAnd condition
You can modify TSQL like
...
AND
(m.MetaData2 = #Device AND #OrAnd = 'AND')
)
OR
(m.MetaData2 = #Device AND #OrAnd = 'OR')
Just make sure you place ')' and '(' correctly, depending on business logic.

Can Any one help me to convert this sql query into linq

I need to convert this SQL Query to Link :
"Select * FROM [Register]
where RegisterId IN (SELECT MyId
FROM Friends
WHERE FriendId='" + Session["CurrentProfileId"] + "'
AND Status=1
UNION
SELECT FriendId
FROM Friends
WHERE MyId='" + Session["CurrentProfileId"] + "'
AND Status=1) ";
It may be look like this??? but this is incorrect and having errors
(from u in db.Register
where RegisterId).Contains
(from f in db.Freinds
where f.MyId == Id && m.Status == 1
select new { m.MyId })
.Union(from m in db.Freinds
where f.FreindId == Id && m.Status == 1
select new { m.CreateDate } ));
You have a few problems with the linq above and here are a few:
In the query in the Union you select the CreateDate whereas in the top on you select the MyId. I assume you meant to select FreindId.
In these 2 queries you create an anonymous class instance with the field but then compare it to the RegisterId which is probably a guid/string/int - but for sure not of the type you just created.
You are using the Contains method wrong. Linq syntax can be similar to sql but it is not the same. Check here for Contains
The correct Linq way of doing it is:
var idsCollection = ((from f in db.Freinds
where f.StatusId == 1 && f.MyId == Id
select f.MyId)
.Union(from m in db.Friends
where m.StatusId == 1 && f.FreindId == Id
select m.FriendId)).ToList();
var result = (from u in db.Register
where idsCollection.Contains(u.RegisterId)
select u).ToList();
Notice that the .ToList() is not a must and is here just to ease in debugging. For more information about this .ToList() and Linq in general check MSDN

Insert not working using MERGE in SQL server

I have a stored proc with the below query to insert/update using a MERGE in SQL Server but the query works fine for update, but its not working for Insert.
Although I gets correct updated records in Target but for new inserts, it fails.
Basically, i have 4 tables.SUPPORT_STAFF_BAK is the target table which needs to be updated from source table UNIQUE_DUP_TEST based on few conditions from other two tables(REF_FUNCTION,DATA_PERIOD) which i tried to fulfill using joins.
Based on the conditions, we need to check in target, if the same ggid exists for current data_period we need to update it else we need to insert new record again, based on the condition.
MERGE SUPPORT_STAFF_BAK AS SUPP_STAFF
USING
(SELECT G_UNIQUE.[GLOBAL_ID],
G_UNIQUE.[FIRST_NAME],
G_UNIQUE.[LAST_NAME],
G_UNIQUE.[EMAIL],
G_UNIQUE.[Gender],
G_UNIQUE.[DATE_OF_BIRTH],
G_UNIQUE.[PRODUCTION_UNIT_CODE],
ORG.[LEGAL_ENTITY_COUNTRY_CODE],
ORG.[LEGAL_ENTITY_COUNTRY],
G_UNIQUE.[JOB_NAME],
ORG.[BU_CODE],
ORG.[BU_NAME],
ORG.[SBU_CODE],
ORG.[SBU_NAME],
G_UNIQUE.[GRADE_LETTER],
CASE
WHEN G_UNIQUE.[EMPLOYEE_STATUS] = 'A' THEN 'Active'
WHEN G_UNIQUE.[EMPLOYEE_STATUS] = 'S' THEN 'Suspended'
WHEN G_UNIQUE.[EMPLOYEE_STATUS]= 'T' THEN 'Terminated'
END AS [EMPLOYEE_STATUS],
CASE WHEN G_UNIQUE.[CATEGORY] = 'DSS' THEN G_UNIQUE.[CATEGORY_DETAIL] ELSE ''
END AS [CATEGORY],
G_UNIQUE.[CATEGORY_DETAIL],
G_UNIQUE.[FIRST_JOINING_DATE],
PERIOD.DATA_PERIOD_ID
FROM UNIQUE_DUP_TEST G_UNIQUE
INNER JOIN GDH_ORG ORG
ON G_UNIQUE.PRODUCTION_UNIT_CODE=ORG.PRODUCTION_UNIT_CODE
INNER JOIN REF_FUNCTION FUNC
ON G_UNIQUE.CATEGORY_DETAIL=FUNC.FUNCTION_CODE
INNER JOIN DATA_PERIOD PERIOD
ON FUNC.FUNCTION_ID=PERIOD.FUNCTION_ID
WHERE PERIOD.DATA_YEAR=YEAR(GETDATE()) AND PERIOD.DATA_MONTH=MONTH(GETDATE())
) AS G_SOURCE
ON SUPP_STAFF.GGID = G_SOURCE.GLOBAL_ID AND SUPP_STAFF.PRODUCTION_UNIT_CODE=G_SOURCE.PRODUCTION_UNIT_CODE
AND SUPP_STAFF.DATA_PERIOD_ID=G_SOURCE.DATA_PERIOD_ID
WHEN MATCHED THEN
UPDATE SET
[SUPP_STAFF].[FIRST_NAME] = G_SOURCE.[FIRST_NAME],
[SUPP_STAFF].[LAST_NAME] = G_SOURCE.[LAST_NAME],
[SUPP_STAFF].[EMAIL] = G_SOURCE.[EMAIL],
[SUPP_STAFF].[GENDER] = G_SOURCE.[Gender],
[SUPP_STAFF].[DATE_OF_BIRTH] = G_SOURCE.[DATE_OF_BIRTH],
[SUPP_STAFF].[LEGAL_ENTITY_COUNTRY_CODE] = G_SOURCE.[LEGAL_ENTITY_COUNTRY_CODE],
[SUPP_STAFF].[LEGAL_ENTITY_COUNTRY_NAME] = G_SOURCE.[LEGAL_ENTITY_COUNTRY],
[SUPP_STAFF].[GCM_ROLE] = G_SOURCE.[JOB_NAME],
[SUPP_STAFF].[BU_CODE] = G_SOURCE.[BU_CODE],
[SUPP_STAFF].[BU_NAME] = G_SOURCE.[BU_NAME],
[SUPP_STAFF].[SBU_CODE] = G_SOURCE.[SBU_CODE],
[SUPP_STAFF].[SBU_NAME] = G_SOURCE.[SBU_NAME],
[SUPP_STAFF].[GRADE] = G_SOURCE.[GRADE_LETTER],
[SUPP_STAFF].[EMPLOYEE_STATUS] = G_SOURCE.[EMPLOYEE_STATUS],
[SUPP_STAFF].[EMPLOYEE_CATEGORY] = G_SOURCE.[CATEGORY],
[SUPP_STAFF].[START_DATE] = G_SOURCE.[FIRST_JOINING_DATE],
[SUPP_STAFF].[UPDATE_DATE] = GETDATE(),
[SUPP_STAFF].[UPDATE_USER] = CASE WHEN G_SOURCE.[EMPLOYEE_STATUS]='Terminated' THEN 'Delete'
WHEN G_SOURCE.[EMPLOYEE_STATUS]<>'Terminated' THEN 'Update'
END,
[SUPP_STAFF].[SUPPORT_STAFF_FUNCTION] = CASE WHEN G_SOURCE.[EMPLOYEE_STATUS]='Terminated' THEN NULL
WHEN G_SOURCE.[EMPLOYEE_STATUS]<>'Terminated' THEN G_SOURCE.[CATEGORY_DETAIL]
END
WHEN NOT MATCHED AND G_SOURCE.[CATEGORY] = 'CC1'
AND G_SOURCE.[EMPLOYEE_STATUS] IN ('A, S')
THEN
INSERT( [GGID],
[FIRST_NAME],
[LAST_NAME],
[EMAIL],
[GENDER],
[DATE_OF_BIRTH],
[LEGAL_ENTITY_COUNTRY_CODE],
[LEGAL_ENTITY_COUNTRY_NAME],
[GCM_ROLE],
[BU_CODE],
[BU_NAME],
[SBU_CODE],
[SBU_NAME],
[GRADE],
[EMPLOYEE_STATUS],
[EMPLOYEE_CATEGORY],
[START_DATE],
[UPDATE_DATE],
[UPDATE_USER],
[SUPPORT_STAFF_FUNCTION]
)
VALUES (
G_SOURCE.[GLOBAL_ID],
G_SOURCE.[FIRST_NAME],
G_SOURCE.[LAST_NAME],
G_SOURCE.[EMAIL],
G_SOURCE.[Gender],
G_SOURCE.[DATE_OF_BIRTH],
G_SOURCE.[LEGAL_ENTITY_COUNTRY_CODE],
G_SOURCE.[LEGAL_ENTITY_COUNTRY],
G_SOURCE.[JOB_NAME],
G_SOURCE.[BU_CODE],
G_SOURCE.[BU_NAME],
G_SOURCE.[SBU_CODE],
G_SOURCE.[SBU_NAME],
G_SOURCE.[GRADE_LETTER],
G_SOURCE.[EMPLOYEE_STATUS],
G_SOURCE.[CATEGORY_DETAIL],
G_SOURCE.[FIRST_JOINING_DATE],
GETDATE(),
'Insert',
G_SOURCE.[CATEGORY_DETAIL]
)
OUTPUT $action,
INSERTED.GGID AS GGID;
SELECT ##ROWCOUNT;
One of your assumptions is wrong. Either the source query has less rows than you think, or there is a match, or the insert condition is not met. Otherwise the query is OK.
To debug this I'd insert the source query into a temp table and manually inspect its contents to make sure they are what you expect.
You can then join to the target to see if your inserts maybe are converted to updates (e.g. select * from Source join Target on ...). Internally, a MERGE is just a full outer join anyway and you can reproduce that manually.
Right now nobody can tell you the exact answer. You need to debug this yourself and examine your data.
Finally I found the error. The error was at the below 2 places -
CASE WHEN G_UNIQUE.[CATEGORY] = 'DSS' THEN G_UNIQUE.[CATEGORY_DETAIL] ELSE '' END AS [CATEGORY],
I replaced it with
CASE WHEN G_UNIQUE.[CATEGORY] = 'DSS' THEN G_UNIQUE.[CATEGORY_DETAIL] ELSE ''
END AS [EMPLOYEE_FUNCTION],
Also I included one more column in my Source query which was missing-
G_UNIQUE.[CATEGORY],
Also, there below wrong code
WHEN NOT MATCHED AND G_SOURCE.[CATEGORY] = 'CC1'
AND G_SOURCE.[EMPLOYEE_STATUS] IN ('A, S')
was replaced by the below correct code-
WHEN NOT MATCHED AND G_SOURCE.[CATEGORY] = 'CC1'
AND G_SOURCE.[EMPLOYEE_STATUS] IN ('Active', 'Suspended')
Actually, I was missing 1 source column and was checking the value for the same while inserting and hence the insert was failing.
Also,in the source for Employee_status i checked the values as A,S and T and then replaced them with Active,Suspended,Terminated but while inserting in the When not matched , i was checking the value for A,S,T which every time was returning false and hence insert failed.

Resources