LIKE function in SQL Server 2008 suggestion needed - sql-server

I have a table Customer with 2 columns Name and Surname (sql Server 2008). User wants to search by Name-Surname - or just typing Jo Bloggs. Suppose a row is filled with
CustomerId Name Surname
1 Jo Bloggs
doing
select * from customer where Name like '%Jo%' will find the records
select * from customer where Surname like '%Bloggs%' will find the records
But How can I make it return records for if user types both Name and Surname eg Jo Bloggs?

You could also create a computed column and search on that:
ALTER TABLE dbo.customer
ADD FullName as Name + ' ' + Surname PERSISTED
Now you'd have an extra column FullName in your customer table, which is always up to date, and you can search for:
SELECT (list of fields) FROM dbo.customer
WHERE Fullname = 'Jo Bloggs'
and since it's a persisted, computed column, you can even put an index on it to make exact searches faster

This should work whether user enters First Name, Surname or both.
SELECT *
FROM customer cus
WHERE ((cus.Name like #FirstName) OR (#FirstName IS NULL)) AND
((cus.Surname like #Surname) OR (#Surname IS NULL))
I used two variables because entering input values into an SQL string is strongly discouraged, as it exposes to SQL Injection (other than being slower).

select * from customer where Name like '%Jo%' and Surname like '%Bloggs%'

select * from customer where Name like '%Jo%'
union
select * from customer where Surname like '%Bloggs%'

Related

Get the result from 3 tables that have the same name of fields

I have 3 tables in SQL Server:
Table MyParents
ID Name Surname
Table MyCousins
ID Name Surname
Table MyGrandParents
ID Name Surname
I would like to ask: is there a way to get the "Name" and "Surname" from all the 3 tables and to know from what table they are coming from in one query?
So the result should be
Name Surname Table
-----------------------------------------
Giovanni Rossi MyParents
Rosanna Blu MyCousins
Seth TheGreat MyGrandParents
Any help is appreciated
You can use UNION ALL and a literal for the table.
SELECT name,
surname,
'MyParents' [table]
FROM MyParents
UNION ALL
SELECT name,
surname,
'MyCousins' [table]
FROM MyCousins
UNION ALL
SELECT name,
surname,
'MyGrandParents' [table]
FROM MyGrandParents;
But note, that your design is probably improvable. There should be only one table for all the people and a linking table storing how they are related.

Obtain Duplicated Data

Please suggest an SQL query to find duplicate customers across different stores, e.g. customer table has id, name, phone, storeid in it, I need to write queries for the following:
Duplicate customers within a store
Duplicate customers across different stores
Table data:
id name phone storeid
-----------------------------------
1 abc 123 4
2 abc 123 4
3 abc 123 5
The first query should show only first 2 records, and the second query should show all 3 records.
You can do something like the following:-
SELECT Name,Phone, COUNT(Id) NumberOfTimes, StoreID
FROM Customers
GROUP BY Name,Phone,StoreID
HAVING COUNT(Id) > 1
ORDER BY StoreID
Hope this helps.
Solution
You can try this for the first query:
SELECT *
FROM customer,
WHERE 1 < (
SELECT COUNT(name)
FROM customer
WHERE name IN (
SELECT name FROM customer
)
) AND
1 < (
SELECT COUNT(storeid)
FROM customer
WHERE storeid IN (
SELECT storeid FROM customer
)
);
Now, for the second query, use the above one, but remove everything after and including the AND.
Explanation
Let's look at the query step-by-step:
SELECT *
FROM customer
This is stating you want all the columns from the customers table.
WHERE 1 < (
SELECT COUNT(name)
FROM customer
WHERE name IN (
SELECT name FROM customer
)
)
This is a pretty long query, so let's look from inside-outward.
WHERE name IN (
SELECT name FROM customer
)
This time we're getting all the names of customers and checking if their is match in our curret table. To be truthful, we might not need this whole section....
SELECT COUNT(name)
FROM customer
This is stating we want the total number of times each name appears (count) in the customers table that matches the where clause.
WHERE 1 < (
....
)
Here, we are comparing the result from the subquery (the number of duplicated names) and checking to see if it is greater than l (i.e., there is a duplicate).
AND
.....
The AND keyword indicates that this second condition must be true in addition to the previous conditions.
The full query should return all entries where both the names and store ids are duplicated; if you remove everything including and after the AND, that will result in all entries which have the same name, but not neccessarily the right store id.
Notes
The other two answers are suggesting grouping duplicated data, but in your particular case, I think you do want the duplicated entries as per your expected results (albeit you should add more expected output info than that).
SELECT storeName, customerName FROM customer
WHERE id IN (
SELECT c.storeid
FROM customer 'c'
RIGHT JOIN store 's' ON (c.storeid = s.id)
GROUP BY c.storeid
HAVING COUNT(*) > 1
)
Basically, we are grouping by storeids, which allows us to count the times they occur in the customer table. We get the id of a case where there are multiple occurrences, and we select the storeName and CustomerName from the customer table that contains the id we got from the inner query.

Checking existance of dynamic value before update/insert

I am trying to mass update a table column with values but I need to get the query to check whether this value already exists. If it does then to make the relevant changes before checking again and updating the table.
The database primarily holds staff information and I need to create a unique username, the script to create the username is :
select upper(LEFT(first_name,1))+LEFT(surname,3)+'1'
from staff_test
If this was used for an example user it would generate a username of ABit1 for user Andrew Bithell. What I need it to do is check to see if there already is a ABit1 username in the STAFF_TEST table and if so change Andrews username to ABit2 as the usernames have to be unique before it moves onto the next user.
I have created another table which lists all the current usernames splitting the existing usernames into 2 columns, so they display in this table as
column1 | column2
------------------
ABit |1
I have experimented with a function and I am now thinking a Merge statement might be the way to go.
Any suggestions are welcomed.
Use row_number can generate all the unique names at once:
select
upper(LEFT(first_name,1))+LEFT(surname,3)+
rtrim(row_number() over (partition by upper(LEFT(first_name,1))+LEFT(surname,3) ))
,first_name
,surname
from staff_test
Perform an up front check to see if there are any clashes:
SELECT UPPER(LEFT(first_name, 1)) + LEFT(surname, 3) + '1' AS username ,
COUNT(1) counter
FROM staff_test
GROUP BY UPPER(LEFT(first_name, 1)) + LEFT(surname, 3) + '1'
HAVING COUNT(1) > 1
ORDER BY COUNT(1) DESC
This will return each username on your staff table, grouped by the username, along with a count of how many occurrences there are of each.
You can either sanitize the data if that's what you're looking to do, otherwise I would suggest, appending an Id column value or some other unique value per record instead of 1 on the end.

T-SQL for Updating Rows with same value in a column

I have a table lets say called FavoriteFruits that has NAME, FRUIT, and GUID for columns. The table is already populated with names and fruits. So lets say:
NAME FRUIT GUID
John Apple NULL
John Orange NULL
John Grapes NULL
Peter Canteloupe NULL
Peter Grapefruit NULL
Ok, now I want to update the GUID column with a new GUID (using NEWID()), but I want to have the same GUID per distinct name. So I want all the John Smiths to have the same GUID, and I want both the Peters to have the same GUID, but that GUID different than the one used for the Johns. So now it would look something like this:
NAME FRUIT GUID
John Apple f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
John Orange f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
John Grapes f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
Peter Canteloupe e3b1851c-1927-491a-803e-6b3bce9bf223
Peter Grapefruit e3b1851c-1927-491a-803e-6b3bce9bf223
Can I do that in an update statement without having to use a cursor? If so can you please give an example?
Thanks guys...
Update a CTE won't work because it'll evaluate per row. A table variable would work:
You should be able to use a table variable as a source from which to update the data. This is untested, but it'll look something like:
DECLARE #n TABLE (Name varchar(10), Guid uniqueidentifier);
INSERT #n
SELECT Name, newid() AS Guid
FROM FavoriteFruits
GROUP BY Name;
UPDATE f
SET f.Guid = n.Guid
FROM #n n
JOIN FavoriteFruits f ON f.Name = n.Name
So that populates a variable with a GUID per name, then joins it back to the original table and updates accordingly.
To clarify comments re a table expression in the USING clause of a MERGE statement.
The following won't work because it'll evaluate per row:
MERGE INTO FavoriteFruits
USING (
SELECT NAME, NEWID() AS GUID
FROM FavoriteFruits
GROUP
BY NAME
) AS source
ON source.NAME = FavoriteFruits.NAME
WHEN MATCHED THEN
UPDATE
SET GUID = source.GUID;
But the following, using a table variable, will work:
DECLARE #n TABLE
(
NAME VARCHAR(10) NOT NULL UNIQUE,
GUID UNIQUEIDENTIFIER NOT NULL UNIQUE
);
INSERT INTO #n (NAME, GUID)
SELECT NAME, NEWID()
FROM FavoriteFruits
GROUP
BY NAME;
MERGE INTO FavoriteFruits
USING #n AS source
ON source.NAME = FavoriteFruits.NAME
WHEN MATCHED THEN
UPDATE
SET GUID = source.GUID;
There's a single-statement solution too, which, however, has some limitations. The idea is to use OPENQUERY(), like this:
UPDATE FavoriteFruits
SET GUID = n.GUID
FROM (
SELECT NAME, GUID
FROM OPENQUERY(
linkedserver,
'SELECT NAME, NEWID() AS GUID FROM database.schema.FavoriteFruits GROUP BY NAME'
)
) n
WHERE FavoriteFruits.NAME = n.NAME
This solution implies that you need to create a self-pointing linked server. Another specificity is that you can't use this method on table variables nor local temporary tables (global ones would do as well as 'normal' tables).

Searching 2 fields at the same time

I have a table of first and last names
firstname lastname
--------- ---------
Joe Robertson
Sally Robert
Jim Green
Sandra Jordan
I'm trying to search this table based on an input that consists of the full name. For example:
input: Joe Robert
I thought about using
SELECT * FROM tablename WHERE firstname LIKE
BUT the table stores the first and last name separately, so I'm not sure how to do the search in this case
In MyISAM:
SELECT *
FROM mytable
WHERE MATCH(firstname, lastname) AGAINST ("Joe* Robert*" IN BOOLEAN MODE);
This will run much faster if you create a FULLTEXT index:
CREATE FULLTEXT INDEX ON mytable (firstname, lastname)
For the query to be able to search the short names (like Joe in your case), you'll need to set the variable ##ft_min_word_len to 1 before creating the index.
In InnoDB you'll need to split the search string:
SELECT *
FROM mytable
WHERE firstname LIKE 'Joe%'
AND lastname LIKE 'Robert%'
An alternative to Quassnoi's method:
SELECT *
FROM mytable
WHERE CONCAT(firstname, " ", lastname) = "Joe Robert"

Resources