I am trying to implement a way to replace "dynamic SQL" of WHERE clause.
That is, to create a temp table, "#FilterTable", which contains my WHERE's name and value.
Then, I use "left join" to map my target table #Hotel with #FilterTable.
However, I got an error when using the following code:
DECLARE #filterName varchar(50)='Id',
#filterValue int =13
CREATE TABLE #Hotel (Id varchar(50), DisplayName varchar(100))
CREATE TABLE #FilterTable (Name varchar(50), Value varchar(100))
INSERT INTO #Hotel(Id,DisplayName) VALUES ('1','California Inn'), ('13','Hilton Hotel')
INSERT INTO #FilterTable(Name,Value) VALUES ('Id','13'),('DisplayName','Hotel')
SELECT a.*
FROM #Hotel a WITH(NOLOCK)
LEFT JOIN #FilterTable b WITH(NOLOCK)
ON #filterName= b.Name
AND
CASE b.Name
WHEN 'Id' THEN CONVERT(varchar(10), a.Id) = b.Value
WHEN 'DisplayName' THEN a.DisplayName like b.Value END
DROP Table #Hotel
DROP Table #FilterTable
It always shows error in
WHEN 'Id' THEN CONVERT(varchar(10), a.Id) = b.Value
WHEN 'DisplayName' THEN a.DisplayName like b.Value END
I know if I change to
WHEN 'DisplayName' THEN CONVERT(varchar(10), a.Id) END = b.Value
, it will pass, but there is no way to add the second condition in "WHEN" clause under this situation.
Does anyone know what is the correct syntax to put those two "WHEN" clause togather?
My db version is SQL SERVER 2014 Enterprise.
Thank you.
Your syntax for CASE is incorrect. You're using it like a switch statement in C, Java, etc. You don't say case against a value, then switch on the value. Rather, it's like an if statement where each condition is independent.
SELECT a.*
FROM #Hotel a WITH(NOLOCK)
LEFT JOIN #FilterTable b WITH(NOLOCK)
ON #filterName= b.Name
AND
CASE
WHEN b.Name = 'Id' AND CONVERT(varchar(10), a.Id) = b.Value THEN 1
WHEN b.Name = 'DisplayName' AND a.DisplayName like b.Value THEN 1
ELSE 0
END = 1
This says, if b.Name is ID and the convert pattern matches, the row matches, or if b.Name is DisplayName and the display name is like b.Value, the row matches.
Give that a try.
I do have to point out that this is likely to not scale well given multiple rows. You should really have a separate query for each case so that SQL Server can use the appropriate indexes and statistics.
In your code:
WHEN 'Id' THEN CONVERT(varchar(10), a.Id) = b.Value
WHEN 'DisplayName' THEN a.DisplayName like b.Value END
= b.Value and like b.Value equals = b.Value. If you want to use LIKE you have to add: like '%' + b.Value + '%'
But if it doesn't mean then you can use:
b.Value = CASE b.Name
WHEN 'Id' THEN CONVERT(varchar(10), a.Id)
WHEN 'DisplayName' THEN a.DisplayName END
Related
I am using the following query to gather some information about each ProductId - note that a ProductId can contain several records in the dbo.Sales table:
SELECT
c.ProductId,
COUNT(*) as NumberOfRecords,
(SELECT
(ISNULL(NULLIF(c.Text, ''), 'FALSE'))) as TextFieldHasData
FROM dbo.Sales c
JOIN dbo.Sources s
ON c.ProductId = s.ProductId
AND s.SourceStatusId in (1,2)
GROUP BY c.ProductId, c.Status, s.SourceStatusId, c.Text
ORDER BY c.ProductId
I need to tweak the ISNULL part of the query, and I'm having trouble with the syntax; what I actually need to do is first check the NumberofRecordscount - if the the NumberofRecords count for a given result record is greater than 1, then the TextFieldHadData field for that record should just say 'N/A'. But, if the NumberofRecordscount for a given result record = 1, then it should check whether the c.Text field is NULL or blank. If it is NULL or Blank, the TextFieldHasData field would say 'FALSE.' If it is not NULL or blank, the TextFieldHasData field would say 'TRUE.'
Looking at your code, perhaps you are looking for something like the following (where you would be grouping up to ProductId level):
SELECT
c.ProductId
, COUNT(*) as NumberOfRecords
,
CASE
WHEN COUNT(*) > 1
THEN 'N/A'
ELSE
CASE
WHEN SUM(CASE WHEN ISNULL(c.Text, '') = '' THEN 0 ELSE 1 END) > 0
THEN 'TRUE'
ELSE 'FALSE'
END
END TextFieldHasData
FROM
dbo.Sales c
JOIN dbo.Sources s ON
c.ProductId = s.ProductId
AND s.SourceStatusId in (1, 2)
GROUP BY c.ProductId
ORDER BY c.ProductId
You can use the query:
I can not validate it as I don't have these tables, but it should work, unless you find a minor syntax error.
The idea is to use "case when ..." sql function
select v.productid,v.NumberOfRecords,
case
when v.NumberOfRecords>1 then 'N/A'
when v.NumberOfRecords=1 and isnull(v.TextFieldHasData,'') ='' then 'FALSE'
else 'TRUE' end [textfieldhasdata]
from(
SELECT
c.ProductId,
COUNT(*) as NumberOfRecords,
(SELECT
(ISNULL(NULLIF(c.Text, ''), 'FALSE'))) as TextFieldHasData
FROM dbo.Sales c
JOIN dbo.Sources s
ON c.ProductId = s.ProductId
AND s.SourceStatusId in (1,2)
GROUP BY c.ProductId, c.Status, s.SourceStatusId, c.Text) v
ORDER BY ProductId
I have a query which is fetching values from multiple tables, it looks some thing close to the below query.
I have highlighted in bold the place where i need to pass the value returned from the same query.
select E.[EmployeeName] as EmployeeName
, (select City from tblEmployeeCities where C.EmployeeID = E.EmployeeID) as EmployeeCity
, (Select State from tblStates **where City = /i need to give the name of
the city returned by the above statement** ) as EmployeeState
from tblEmployees E
Use JOIN/LEFT JOIN:
SELECT E.EmployeeName, C.City, S.State
FROM tblEmployees E
LEFT JOIN tblEmployeeCities C ON C.EmployeeID=E.EmployeeID
LEFT JOIN tblStates S ON S.City=C.City
Maybe something like
select E.[EmployeeName] as EmployeeName
, c.City as EmployeeCity
, (Select State from tblStates where City = c.City ) as EmployeeState
from tblEmployees E
inner join tblEmployeeCities C on C.EmployeeID = E.EmployeeID
I think this can be achieved with a CASE WHEN ELSE END statment in the select part of your sql statment.
Look at example here for syntax or usage: https://www.w3schools.com/sql/func_mysql_case.asp
I have two tables with same columns.
Table A have ID, Name, Des, Status and
Table B have ID, Name, Des, Status.
I want to compare data any field of Table B with Table A, except column ID because same.
As same picture above, when FETCH data of Table B, detect data of ID ID001 and ID003 not same, idea of my mind same
IF (SELECT COUNT (SELECT * FROM TABLE A RIGHT JOIN TABLE B ON A.ID = B.ID) != 0)
BEGIN
PRINT 'BLAH BLAH, NOT SAME'
END
If you have idea or solution, share for me, Thank you so much.
You can use CHECKSUM or BINARY_CHECKSUM:
SELECT a.*, b.*
FROM TableA a INNER JOIN TableB b ON b.ID = a.ID
WHERE CHECKSUM(b.Name, b.Des, b.Status) <> CHECKSUM(a.Name, a.Des, a.Status)
See also this link. It should be faster then multiple OR conditions.
IF (SELECT COUNT(*)
FROM TableA a INNER JOIN TableB b ON b.ID = a.ID
WHERE BINARY_CHECKSUM(b.Name, b.Des, b.Status)
<> BINARY_CHECKSUM(a.Name, a.Des, a.Status)
>0
PRINT 'Not the same.'
Since it is not too much clear how do you want to show your differences, this is one approach:
SELECT A.ID,
(CASE WHEN A.Name <> B.Name THEN 'Diff Name' ELSE '') NameCompare,
(CASE WHEN A.Des <> B.Des THEN 'Diff Des' ELSE '') DESCompare,
(CASE WHEN A.Status <> B.Status THEN 'Diff Status' ELSE '') StatusCompare
FROM A
INNER JOIN B
ON A.ID = B.ID
This is a simple join
To get all different rows, you can say:
select a.*, b.*
from TableA a inner join TableB b on b.ID = a.ID
where b.Name <> a.Name or b.Des <> a.Des or b.Status <> a.Status
I have 2 name columns from table1.name and table2.name. I have names in table1.name like "Alex Testing" and in table2.name it's "Alexander Testing". I have the table do some other tricky stuff but it doesn't recognize that Alex and Alexander are the same people so it will not include the name in my report. I was wondering if there was a way I could get these 2 to inner join by first name or even by last name, like if another table had the same first name but different last name?
I've tried:
SELECT
Table1.[Name], Table2.[Time],
CASE WHEN myvariables here then 0 ELSE 1 END AS columnB
INTO NewTable
FROM
Table1 INNER JOIN Table2
ON Table1.[Name] LIKE ('%' + Table2.Name + '%')
however it still does not work, it wont recognize Alex's name.
I've also tried:
SELECT
Table1.[Name], Table2.[Time],
CASE WHEN myvariables here THEN 0 ELSE 1 END as columnB
INTO NewTable
FROM
Table1 INNER JOIN Table2
ON Table1.[Name] LIKE CONCAT('%',"Table2.Name", '%')
Try:
SELECT
Table1.[Name], Table2.[Time],
CASE WHEN myvariables here then 0 ELSE 1 END AS columnB
INTO NewTable
FROM
Table1 INNER JOIN Table2
ON SUBSTRING(Table1.[Name], CHARINDEX(' ', Table1.[Name]) + 1, LEN(Table1.[Name])) = SUBSTRING(Table2.[Name], CHARINDEX(' ', Table2.[Name]) + 1, LEN(Table2.[Name]))
If you have large volume tables you may want to use subqueries and select directly lastnames, and then use a join on lastnames.
Why do I get "Incorrect syntax near the keyword 'IF'" in the following SQL?:
use AdventureWorks
CREATE FUNCTION Query2_Function(#DPT INT)
RETURNS TABLE
AS
RETURN
IF #DPT is not null
select edh.departmentid,d.name,count(*)as cnt
From HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh on e.employeeID = edh.employeeid
inner join humanresources.department d on edh.departmentid = d.departmentid
where d.Name = #dpt
group by edh.departmentid, d.name
You cannot have any flow of control statements in inline table valued functions. If #dpt is null the query will return an empty result set anyway
Edit: or at least would if the correct datatype. You have #DPT INT and are comparing against a name column. That seems doomed to failure at execution time.
Edit 2:
As a solution, you could 1) simply drop the IF #DPT is not null line and 2) either
change the #DPT parameter's type from INT to something like varchar(100), if the function was supposed to search for the department by name,
or
change the WHERE clause to something like this:
where d.departmentid = #dpt
if you meant it to search by department ID.
Try this
CREATE FUNCTION Query2_Function(#DPT INT)
RETURNS #tbl TABLE
(
departmentid int ,
[name] varchar(100),
cnt int
)
AS
begin
IF #DPT is not null
insert into #tbl (departmentid,name,cnt)
select edh.departmentid,d.name,count(*)as cnt
From HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh on e.employeeID = edh.employeeid
inner join humanresources.department d on edh.departmentid = d.departmentid
where d.DepartmentID =#DPT
group by edh.departmentid, d.name
return
end
GO