Writing SQL code: same functionality as Yell.com - sql

Can anyone help me with the trying to write SQL (MS SqlServer) - I must admit this is not by best skill.
What I want to do is exactly the same functionality as appears for the search boxes for the Yell website i.e.
Search for company type
AND/OR company name
AND/OR enter a company name
in a Location
if anyone can suggest the SQL code you would need to write in order to get the same functionality as Yell - that would be great.

Typically, one does something like this:
-- All these are NULL unless provided
DECLARE #CompanyType AS varchar
DECLARE #CompanyName AS varchar
DECLARE #Town AS varchar
SELECT *
FROM TABLE_NAME
WHERE (#CompanyType IS NULL OR COMPANY_TYPE_COLUMN LIKE '%' + #CompanyType + '%')
AND (#CompanyName IS NULL OR COMPANY_NAME_COLUMN LIKE '%' + #CompanyName + '%')
AND (#Town IS NULL OR TOWN_COLUMN LIKE '%' + #Town + '%')
Or this (only match start of columns with the wildcards):
-- All these are NULL unless provided
DECLARE #CompanyType AS varchar
DECLARE #CompanyName AS varchar
DECLARE #Town AS varchar
SELECT *
FROM TABLE_NAME
WHERE (#CompanyType IS NULL OR COMPANY_TYPE_COLUMN LIKE #CompanyType + '%')
AND (#CompanyName IS NULL OR COMPANY_NAME_COLUMN LIKE #CompanyName + '%')
AND (#Town IS NULL OR TOWN_COLUMN LIKE #Town + '%')

Can you provide the database layout (schema) that the sql would run against? It would be necessary to give you an exact result.
But generally speaking what you are looking for is
SELECT * FROM tablename WHERE companyType = 'type' OR companyName = 'companyName'

What you need first is not SQL code, but a database design. Only then does it make any sense to start writing SQL.
A simple table schema that matches Yell's functionality might be something like:
CREATE TABLE Company (
company_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
company_name VARCHAR(255) NOT NULL,
location VARCHAR(255) NOT NULL
)
and then you'd search for it by name with SQL like:
SELECT * FROM Company WHERE company_name like '%text%'
or by location like:
SELECT * FROM Company WHERE location = 'Location'
Of course, a real-world location search would have to use either exact city and state, or a zip code lookup, or some intelligent combination thereof. And a real table would then have lots more fields, like descriptions, etc. But that's the basic idea.

Related

WHERE clause with OR operator not giving intended result

I want to write a stored procedure for a search function. I have a database of movies and I should be able to search a movie by Movie.Name, Movie.Producer, Movie.Director and appearing Cast.Name.
CREATE PROCEDURE RetrieveSearchResults
#tokenParam VarChar
AS
Select *
from
(Movie
join
Cast on Movie.MovieID = Cast.MovieID)
join
Actor on Actor.ActorID = Cast.ActorID
where
(Movie.Name like '%' + #tokenParam + '%')
or (Movie.Producer like '%' + #tokenParam + '%')
or (Movie.Director like '%' + #tokenParam + '%')
or (Actor.Name like '%' + #tokenParam + '%')
Upon execution
RetrieveSearchResults 'Almighty'
I get almost all tuples with no similar literal as 'Almighty'
Am I missing something?
Try declaring the varchar limit. VARCHAR(100) or something like that. It may be making assumptions on the length and cutting it down to a VARCHAR(1) or similar. The problem with declaring VARCHAR without a length is the system will assign for you and it may not be what you expect.

sql full text search with nullable parameter

We would like to work with full-text search but keep the incoming parameters in our procedure null-able. In this example #Street can have a value like Heuvel or can be NULL.
Working this out in a query is something that doesn't work.
heuvel* gives all the rows that are expected.
* gives zero rows while other threads on forums say that it will give all rows
street = isnull(#street, street) gives all rows
Knowing all the above I would think this query would work. It does but it's VERY slow.
When I execute the or clause separately then the query is fast.
Declare #Street nvarchar(50)= '"heuvel*"'
Declare #InnerStreet nvarchar(50) = '"'+ isnull(#Street, '') +'*"';
SELECT *
FROM Address
WHERE street = isnull(#street, street) or CONTAINS(street, #InnerStreet)
Now the question is, how to work with full-text search and null-able parameters?
Try this. #street is either NULL or has a value.
declare #streetWildcard nvarchar(50) = '"' + #street + '*"'
SELECT *
FROM Address
WHERE (#street is NULL) or CONTAINS(street, #streetWildcard)
If the performance is still bad then the execution plan may not be short circuiting the WHERE condition. In that case, try this instead.
if (#street is NULL) begin
SELECT *
FROM Address
end
else begin
declare #streetWildcard nvarchar(50) = '"' + #street + '*"'
SELECT *
FROM Address
WHERE CONTAINS(street, #streetWildcard)
end

Use LIKE for strings in sql server 2008

I want to make a function that search in a table and returns rows that contain a certain word that I Insert like below. But when I use LIKE it give me an error: Incorrect syntax near '#perberesi'
CREATE FUNCTION perberesit7
(#perberesi varchar(100))
RETURNS #menu_rest TABLE
(emri_hotelit varchar(50),
emri_menuse varchar(50),
perberesit varchar(255))
AS
Begin
insert into #menu_rest
Select dbo.RESTORANTET.Emri_Rest, dbo.MENU.Emri_Pjatës, dbo.MENU.Pershkrimi
From RESTORANTET, MENU
Where dbo.MENU.Rest_ID=dbo.RESTORANTET.ID_Rest and
dbo.MENU.Pershkrimi LIKE %#perberesi%
return
End
Pleae help me...How can I use LIKE in this case
try using:
'%' + #perberesi + '%'
instead of:
%#perberesi%
Some Examples
Ok, I just realized that you are creating a function, which means that you can't use INSERT. You should also really take Gordon's advice and use explicit joins and table aliases.
CREATE FUNCTION perberesit7(#perberesi varchar(100))
RETURNS #menu_rest TABLE ( emri_hotelit varchar(50),
emri_menuse varchar(50),
perberesit varchar(255))
AS
Begin
return(
Select R.Emri_Rest, M.Emri_Pjatës, M.Pershkrimi
From RESTORANTET R
INNER JOIN MENU M
ON M.Rest_ID = R.ID_Rest
Where M.Pershkrimi LIKE '%' + #perberesi + '%')
End
Why do you have to define the return table?
The following is a inline table variable function that performs better than a multi-line table. I wrote one to return columns that have the two letters 'id'. Just modify for your own case.
See article from Wayne Sheffield.
http://blog.waynesheffield.com/wayne/archive/2012/02/comparing-inline-and-multistatement-table-valued-functions/
-- Use tempdb
use tempdb;
go
-- Simple ITVF
create function search_columns (#name varchar(128))
returns TABLE
return
(
select * from sys.columns where name like '%' + #name + '%'
)
go
-- Call the function
select * from search_columns('id');
go
However, since you have a '%' in the like clause at the front of the expression, a full table or index scan is likely. You might want to look at full text indexing if you data is large.
http://craftydba.com/?p=1629

Build dynamic query according to variable value

I am using SQL Server 2008 R2.
I am facing problem while fetching records from database in Role Based Access.
I have a Table let us say TableA. I have 5 Columns in it i.e, ID (primary key), FirstName, LastName, RegistrationNumber, EmployeeIdent.
All the columns except ID are of Varchar type.
I have a stored procedure to search the records. I am passing string to it and finding matching records from all five columns.
Now, the problem I am facing is in Role Based Access.
The requirement is when user is of "Admin" type then find matching records from all five columns but when is of "naive" user type then search matching records from only ID column.
I have passed the variable #userType to stored procedure from which I can determine the user type.
One way to resolve this problem is If Condition. Like if (#userType) = 'Admin' then some query Else Some other.
But I don't want to write query in If Condition.
Another way to resolve this is to store query in varchar type of variable and then execute is using EXEC (), but I have heard that it creates more overhead on server (I am not sure about it).
So any other way to fulfill this requirement?
The query to search records is
DECLARE #SearchText VARCHAR(MAX)= ''
SELECT *
FROM TableA
WHERE
Convert(varchar,ID) LIKE CASE WHEN LEN(#SearchText) = 0 THEN Convert(varchar,ID) ELSE '%'+ ISNULL(#SearchText,'0') + '%' END OR
FirstName LIKE CASE WHEN LEN(#SearchText) = 0 THEN FirstName ELSE '%'+ ISNULL(#SearchText,'') + '%' END OR
LastName LIKE CASE WHEN LEN(#SearchText) = 0 THEN LastName ELSE '%'+ ISNULL(#SearchText,'') + '%' END OR
RegistrationNumber LIKE CASE WHEN LEN(#SearchText) = 0 THEN RegistrationNumber ELSE '%'+ ISNULL(#SearchText,'') + '%' END OR
EmployeeIdent LIKE CASE WHEN LEN(#SearchText) = 0 THEN EmployeeIdent ELSE '%'+ ISNULL(#SearchText,'') + '%' END
SELECT
*
FROM TABLEA
WHERE
(#userType = 'admin'
--add any other criteria for admin type here
) or (
#userType = 'naive'
--add any other criteria for naive type here
)

Efficiently Handling Multiple Optional Constraints in Where Clause

This is somewhat of a sequel to Slow Exists Check. Alex's suggestion works and successfully avoids code repetition, but I still end up with a second issue. Consider the example below (From AlexKuznetsov). In it, I have two branches to handle 1 contraint. If I had 2 optional constraints, I would end up with 4 branches. Basically, the number of branches increases exponentially with the number of constraints.
On the other hand, if I use a Multi-Statement Table-valued function or otherwise use temporary tables, the SQL query optimizer is not able to assist me, so things become slow. I am somewhat distrustful of dynamic SQL (and I've heard it is slow, too).
Can anyone offer suggestions on how to add more constraints without adding lots of if statements?
Note: I have previously tried just chaining x is null or inpo = #inpo together, but this is very slow. Keep in mind that while the inpo = #inpo test can be handled via some sort of indexing black magic, the nullity test ends up being evaluated for every row in the table.
IF #inpo IS NULL BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
ORDER BY c;
END ELSE BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
WHERE inpo = #inpo
ORDER BY c;
END
Variation Two: 2 constraints:
IF #inpo IS NULL BEGIN
IF #inpo2 IS NULL BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
ORDER BY c;
END ELSE BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
WHERE inpo2 = #inpo2
ORDER BY c;
END
END ELSE BEGIN
IF #inpo2 IS NULL BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
WHERE inpo = #inpo
ORDER BY c;
END ELSE BEGIN
SELECT a,b,c
FROM dbo.ReuseMyQuery(#i1)
WHERE inpo = #inpo AND
inpo2 = #inpo2
ORDER BY c;
END
END
this is the best reference: http://www.sommarskog.se/dyn-search-2005.html
In such cases I use sp_executesql as described in Erland's article: Using sp_executesql
Whenever dynamic SQL is used, missing permissions may be a problem, so I have a real network account for unit testing, I add that account to the actual role, and I impersonate with that real account whenever I test dynamic SQL, as described here: Database Unit Testing: Impersonation
Here's a rough example. Modify the LIKE statements in the WHERE clause depending if you want "starts with" or "contains" or an exact match in your query.
CREATE PROCEDURE dbo.test
#name AS VARCHAR(50) = NULL,
#address1 AS VARCHAR(50) = NULL,
#address2 AS VARCHAR(50) = NULL,
#city AS VARCHAR(50) = NULL,
#state AS VARCHAR(50) = NULL,
#zip_code AS VARCHAR(50) = NULL
AS
BEGIN
SELECT [name],
address1,
address2,
city,
state,
zip_code
FROM my_table
WHERE ([name] LIKE #name + '%' OR #name IS NULL)
AND (address1 LIKE #address1 + '%' OR #address1 IS NULL)
AND (address2 LIKE #address2 + '%' OR #address2 IS NULL)
AND (city LIKE #city + '%' OR #city IS NULL)
AND (state LIKE #state + '%' OR #state IS NULL)
AND (zip_code LIKE #zip_code + '%' OR #zip_code IS NULL)
ORDER BY [name]
END
GO
Select blah from foo
Where (#inpo1 is null or #inpo1 = inpo1)
and (#inpo2 is null or #inpo2 = inpo2)
Apparently this is too slow. Interesting.
Have you considered code generation? Lengthy queries with lots of duplication is only an issue if it has to be maintained directly.
I realise your question may be purely academic, but if you have real world use cases have you considered only providing optimised queries for the most common scenarios?