T-SQL inner query like join based off IN results - sql

I have a T-SQL query that has a subquery listing 2 names:
Coop
Bro
Code:
Select LastName
From Managers
Where Type = prefix;
I need to have the outer query use this above sub-query in something like an 'IN' statement, but it's not an exact match, but rather a BEGINS WITH. Something like the following with + '%':
Select *
From Employees
Where LastName In (Select LastName + '%'
From Managers
Where Type = prefix)
Desired query would return back outer query results such as:
Cooper
Coopersmith
Coopmoth
Brown
Brownly
Bronnan
...but, this is not working. I get 0 results.

You can use exists. Presumably, you intend something like this:
Select e.*
from Employees e
where exists (select 1
from managers m
where type = prefix and
e.LastName like m.LastName + '%'
)

Got it with similar to:
select * from employees e
inner join Managers m on e.lastname like m.lastname + '%' and m.type = prefix

Related

Full outer join not including results from the second table?

I have 2 employee tables and trying to look up a user from both of them. For example:
Employees1
username full_name
fbar Foo Bar
Employees2
email full_name
sname#test.com Some Name
I'm trying to do something like this:
DECLARE #testuser VARCHAR(100)
SET #testuser = 'sname'
SELECT isnull(a.full_name, b.full_name) as full_name
FROM Employees1 as a
FULL OUTER JOIN Employees2 as b ON b.email LIKE #testuser + '%'
WHERE a.username = #testuser
If I run this then it comes out blank. But if I run the following then it shows the correct name:
SELECT full_name FROM Employees2 WHERE email LIKE #testuser + '%'
Is there a reason the full outer join isn't showing a result but the second select statement is?
If you have limiting conditions on individual tables that are separate from the outer join condition, you will need to put them in a subselect for them to work as expected.
I believe what you want is something like:
DECLARE #testuser VARCHAR(100) = 'sname'
SELECT isnull(a.full_name, b.full_name) as full_name
FROM (
SELECT *
FROM Employees1
WHERE username = #testuser
) as a
FULL OUTER JOIN (
SELECT *
FROM Employees2
WHERE email LIKE #testuser + '%'
) as b
ON b.full_name = a.full_name
Or perhaps you may just need a UNION:
SELECT full_name
FROM Employees1
WHERE username = #testuser
UNION
SELECT full_name
FROM Employees2
WHERE email LIKE #testuser + '%'
I added the full_name join condition, as I believe that is what you intended.
See this db<>fiddle.

SQL hierarchyid type issue

The full task sounds like this: Display the content of employees whose immediate supervisor is younger and less employed in the company.
Columns:
Manager Name | Date of hiring a manager | Head's date of birth
Employee name | Employee hiring date | Employee's date of birth
I already broke my head here:
SELECT
LastName + ' ' + FirstName AS SupervisorFullName,
HireDate,
BirthDate,
(SELECT LastName + ' ' + FirstName
FROM HumanResources.Employee AS subHrE
WHERE HrE.OrganizationNode.IsDescendantOf(subHrE.OrganizationNode) = 1
AND HrE.OrganizationLevel = HrE.OrganizationNode.GetLevel() + 1) AS EmployeeFullName,
(SELECT HireDate
FROM HumanResources.Employee AS subHrE
WHERE HrE.OrganizationNode.IsDescendantOf(subHrE.OrganizationNode) = 1
AND HrE.OrganizationLevel = HrE.OrganizationNode.GetLevel() + 1) AS HireDateEmp,
(SELECT BirthDate
FROM HumanResources.Employee AS subHrE
WHERE HrE.OrganizationNode.IsDescendantOf(subHrE.OrganizationNode) = 1
AND HrE.OrganizationLevel = HrE.OrganizationNode.GetLevel() + 1) AS BithDateEmp
FROM
HumanResources.Employee as HrE
JOIN
Person.Person as P ON HrE.BusinessEntityID = P.BusinessEntityID
ORDER BY
SupervisorFullName ASC
Output
AdventureWork2016 db is used for work
Full Schema AW2016
There's definitely a certain way to think about use of hierarchyid that, once you get the hang of it, opens a lot of possibilities. Here's what I came up with:
WITH FullPerson AS (
SELECT CONCAT_WS(' ', p.FirstName, p.MiddleName, p.LastName) AS [FullName],
e.HireDate,
e.BirthDate,
e.OrganizationNode
FROM HumanResources.Employee AS e
JOIN Person.Person AS p
ON p.BusinessEntityID = e.BusinessEntityID
)
SELECT
manager.OrganizationNode.ToString(),
manager.FullName,
manager.HireDate,
manager.BirthDate,
subordinate.OrganizationNode.ToString(),
subordinate.FullName,
subordinate.HireDate,
subordinate.BirthDate
FROM FullPerson AS subordinate
JOIN FullPerson AS manager
ON subordinate.OrganizationNode.GetAncestor(1) = manager.OrganizationNode
WHERE manager.HireDate > subordinate.HireDate
AND manager.BirthDate > subordinate.BirthDate;
Breaking it down, I create a common table expression to join Employee and Person as I'll need columns from both tables for both subordinates and their managers. The real trick is the join condition. subordinate.OrganizationNode.GetAncestor(1) = manager.OrganizationNode says "take the subordinate's OrganizationNode and go one level up the tree". What's amazing to me is that this sort of query can be supported by indexes and indeed there is an index on that column in the AdventureWorks schema! In addition to the columns you asked for, I added a human-readable representation of OrganizationNode to help with the visualization of how the data relates.

Search 'AS' alias in SQL Server

I have a sql query that pulls the customers full name from the customers table based on the customer ID in the sales table and binds the info to an asp.net listview. I now want to search the records by the customers full name. I used the query below but it keeps telling me that the column "Fullname" is an invalid column name. How do I go about modifying this query to work?
SELECT
tbl_Sales.SaleID, tbl_Sales.CustomerID,
(SELECT Firstname + ' ' + Lastname
FROM tbl_Customers
WHERE CustomerID = tbl_Sales.CustomerID) AS CustomerName,
tbl_Sales.Price
FROM
tbl_Sales
WHERE
CustomerName LIKE '%John%'
Thanks in advance.
You cannot use the Alias name in the same select statement because where will be processed before the select.
Make the original query as sub select and use the alias name in where clause.Try this.
SELECT *
FROM (SELECT tbl_Sales.SaleID,
tbl_Sales.CustomerID,
(SELECT Firstname + ' ' + Lastname
FROM tbl_Customers
WHERE CustomerID = tbl_Sales.CustomerID) AS CustomerName,
tbl_Sales.Price
FROM tbl_Sales) A
WHERE CustomerName LIKE '%John%'
or use Cross apply
SELECT tbl_Sales.SaleID,
tbl_Sales.CustomerID,
t.CustomerName,
tbl_Sales.Price
FROM tbl_Sales
CROSS apply (SELECT Firstname + ' ' + Lastname AS CustomerName
FROM tbl_Customers
WHERE CustomerID = tbl_Sales.CustomerID) t
WHERE t.CustomerName LIKE '%John%'
You are not allowed to pass ALIAS name in WHERE clause instead of that you should use JOIN
Try this:
SELECT S.SaleID, S.CustomerID, (C.Firstname + ' ' + C.Lastname) AS CustomerName, S.Price
FROM tbl_Sales S
INNER JOIN tbl_Customers C ON S.CustomerID = C.CustomerID
WHERE (C.Firstname + ' ' + C.Lastname) LIKE '%John%'
Instead of checking the combined value, you could check each column like this. Combining the columns and comparing is not SARGable, and will result in bad performance:
SELECT
tbl_Sales.SaleID,
tbl_Sales.CustomerID,
cus.Firstname + ' ' + cus.Lastname CustomerName,
tbl_Sales.Price
FROM
tbl_Sales
JOIN
tbl_Customers cus
ON
cus.CustomerID = tbl_Sales.CustomerID
WHERE
(cus.Firstname LIKE '%John%' or
cus.Lastname LIKE '%John%')

SQL Server Full Text Search - Create one computed column

I am currently working on a project where I want to search for employees via just one input search term. For this I am using the SQL FTS.
The table schema looks like this
Employee table
EmployeeId, Firstname, Lastname
Sample data
1, John, Miller
2, Chuck, Norris
Address table
AddressId, EmployeeId, CityId, Street, StreetNumber
Sample data
1, 1, 1, Avenue, 12
2, 2, 2, Wimbledon Rd, 12
City table
CityId, Name, ZipCode
Sample data
1, Hamburg, 22335
2, London, 12345
So now I got the following search term:
John Hamburg: Means John AND Hamburg and should return 1 record.
John London: Means John AND London and should return 0 records since there is no John in London.
Norris Wimbledon: Means Norris AND Wimbledone and should return 1 records.
Now the problem with this is that using CONTAINSTABLE only allows to search one table at a time. So applying "John AND Hamburg" on the Employee Full text catalog returns 0 records since "Hamburg" is located in the address table.
So currently I can use "OR" instead of "AND" only, like:
SELECT
(keyTblSp.RANK * 3) AS [Rank],
sp.*
FROM Employee sp
INNER JOIN
CONTAINSTABLE(Employee, *, 'John OR Hamburg', 1000) AS keyTblSp
ON sp.EmployeeId = keyTblSp.[KEY]
UNION ALL
SELECT
(keyTbl.RANK * 2) AS [Rank],
sp.*
FROM Employee sp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId
INNER JOIN
CONTAINSTABLE([Address], *, 'John OR Hamburg', 1000) AS keyTbl
ON addr.AddressId = keyTbl.[KEY]
UNION ALL
SELECT
(keyTbl.RANK * 2) AS [Rank],
sp.*
FROM Employee sp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId
LEFT OUTER JOIN [City] cty ON cty.CityId = addr.CityId
INNER JOIN
CONTAINSTABLE([City], *, 'John OR Hamburg', 1000) AS keyTbl
ON cty.CityId = keyTbl.[KEY]
This causes that not just John who lives Hamburg is returned, but every person named John and every person who lives in Hamburg.
One solution I could think of is to somehow compute a column in the Employee Table that holds all necessary values for the full text search like.
Employee table
EmployeeId, Firstname, Lastname, FulltextColumn
Sample data
1 | John | Miller | John Miller Avenue 12 Hamburg 22335
So then I could do
SELECT
(keyTbl.RANK) AS [Rank],
sp.*
FROM Employee sp
INNER JOIN
CONTAINSTABLE([Employee], FulltextColumn, 'John AND Hamburg', 1000) AS keyTbl
ON sp.EmployeeId = keyTbl.[KEY]
Is this possible? Any other ideas?
you could use a join to require a match in both the address and the persons name.
SELECT
(keyTblSp.RANK * 3) AS [Rank],
sp.*
FROM Employee sp
INNER JOIN
CONTAINSTABLE(Employee, *, 'John OR Hamburg', 1000) AS keyTblSp
ON sp.EmployeeId = keyTblSp.[KEY]
join
(
SELECT
(keyTbl.RANK * 2) AS [Rank],
sp.*
FROM Employee sp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId
INNER JOIN
CONTAINSTABLE([Address], *, 'John OR Hamburg', 1000) AS keyTbl
ON addr.AddressId = keyTbl.[KEY]
UNION ALL
SELECT
(keyTbl.RANK * 2) AS [Rank],
sp.*
FROM Employee sp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId
LEFT OUTER JOIN [City] cty ON cty.CityId = addr.CityId
INNER JOIN
CONTAINSTABLE([City], *, 'John OR Hamburg', 1000) AS keyTbl
ON cty.CityId = keyTbl.[KEY]
) addr_matches
on addr_matches.EmployeeId = sp.EmployeeId
which I think would give you the results you specified, obviously though, this requires both a name and an address search term for a search to return any results. You didn't specify what happens if someone just searches for 'John', if you will always get both a name and address the above will work fine I think.
I think the computed column is your best option. It'll be the most flexible, given that you don't know which tokens will be in the search query, it'll perform better, and your stored procedure will be smaller.
In order to create a computed column based on data in another table, you will have to create it using a UDF (user defined function) like this:
CREATE FUNCTION dbo.udf_ComputedColumnFunction (
#EmployeeId INT
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #RET VARCHAR(1000)
SELECT
#RET = e.FirstName + ' ' + e.LastName + ' ' + a.Street + ' ' + a.StreetNumber + ' ' + c.Name + ' ' + c.ZipCode
FROM Employee e
INNER JOIN Address a ON a.EmployeeId = e.EmployeeId
INNER JOIN City c ON c.CityId = a.CityId
RETURN #RET
END
GO
ALTER TABLE Employee
ADD SearchColumn AS dbo.udf_ComputedColumnFunction(EmployeeId)
If you don't want to do that, you could:
Create an indexed view and add the FullText index onto that.
Create a lookup table populated by a trigger or by periodically running a stored procedure.
I think you should create and index view and should join all the columns which can be used in FullText to be combined in one single column by separating them with spaces or dashes, as both are noise words for sql server 2005. Then on that indexed view create a full text index.
Contains table does not by default applies FormsOf Inflectional or Forms of Thesaurus. These two are good options to configure and use.
If you want to go only for "OR" then use FreeTextTable as if by default applies both Forms of Thesaurus and FormsOf inflectional.

How to join 2 tables based on a like in mysql

I have 2 tables Employee and Company_Employee.
Employee:
ID, FirstName
Company_Employee:
ID, Company_ID, Employee_ID
I want to do a search by First Name. I was thinking my query would look like:
select FirstName, ID from Employee where FirstName LIKE '%John%' and ID in (select id from Company_Employee)
This query returns no rows. Does anyone know how I can get the rows with a like by FirstName with these 2 tables?
Thanks!
Your query compares a company_employee.id with an employee.id. It should probably compare employee.id with company_employee.employee_id.
You can rewrite the query more clearly with a join:
select *
from employee e
join company_employee ce
on e.id = ce.Employee_ID
where e.FirstName like '%John%'
Something like this
SELECT
*
FROM
Employee e
INNER JOIN Company_Employee ce JOIN ON e.Id = ce.Id)
WHERE
FirstName LIKE '%JOHN%'