Simple select with trick - sql

I need to write a select which will list all of the Clients however here is trick if client has status 1 or 2 it should mark this client with * before name. It should looks like
Vasya Pupkin
* Masha Pupkina
select looks like
select FirstName + ' '+ LastName, Address, DOB
from Clients
Order By FirstName
that means Masha is active client.
Spend almost 2 hours for searching in internet but cannot find anything useful. Because of that asking question here.

You need to rely on the use of the CASE structure to check the status field.
Check this fully functional code with sample data on SQL Fiddle
SELECT (CASE
WHEN status IN (1, 2) THEN '* '
ELSE ''
END) + FirstName + ' '+ LastName as Client_List
FROM Clients
ORDER BY FirstName
Data:
[id] [status] [FirstName] [LastName]
1 3 Vasya Pupkin
2 2 Masha Pupkina
3 3 Sasha Alexeivich
4 1 Katya Alexeivna
Result:
CLIENT_LIST
* Katya Alexeivna
* Masha Pupkina
Sasha Alexeivich
Vasya Pupkin
EDIT
Ouch! too late, muhmud answer is correct

select (case when status in (1, 2) then '* ' else '' end) + FirstName + ' '+ LastName, Address, DOB
from Clients
Order By FirstName

Related

SQL WHERE CONTAINS statement referencing columns not static text

I have these data below:
FName | Lname | Notes | Flag
----- ----- ----- ----
John Smith John Smith didn't know 1
Bill Jones Tom Johnson knows 0
I need to create and populate a variable (Flag) which looks at the Notes column, searches for values in Fname and Lname column, and assigns a 1 if Notes contains both Fname and Lname values, or 0 if it contains only 1, or none of the values from Fname and Lname.
I have looked at CONTAINS, LIKE, and INSTR, but I am having trouble with the references, the examples I see want me to enter a static value to search on ("John"), rather than a column reference ("Fname").
I'd like to write a CASE statement that says
Look in each row, if the Notes field contains the values in the Fname and Lname fields, Flag =1, else, Flag =0.
I have tried
CASE
WHEN
(
SELECT
Fname, Lname, Notes
FROM
table
WHERE CONTAINS ((Notes, Fname) AND (Notes, Lname)) > 0
)
THEN '1' ELSE '0' END
AS Flag
FROM table;
Any help is appreciated. Thank you !
Not sure if the coalesce/isnull is necessary.
select
case
when ((Notes like '%' + coalesce(u.FName,'') + '%') and (Notes like '%' + coalesce(LName,'') + '%'))
then 1
else 0
end Flag
from Table
update t
set t.Flag =
case
when ((Notes like '%' + coalesce(u.FName,'') + '%') and (Notes like '%' + coalesce(LName,'') + '%'))
then 1
else 0
end
From Table t
You were close:
SELECT
CASE WHEN
t.Notes LIKE '%' + t.FName + '%'
AND
t.Notes LIKE '%' + t.LName + '%'
THEN 1
ELSE 0 END AS Flag
FROM
table AS t
However, if you really just want to filter where the Flag = 1, you don't need this as a column:
SELECT
*
FROM
table AS t
WHERE
CASE WHEN
t.Notes LIKE '%' + t.FName + '%'
AND
t.Notes LIKE '%' + t.LName + '%'
THEN 1
ELSE 0 END =1

Compare columns of same table in sql server

I'm trying to compare the columns of a table and fetch the unmatched rows.Can someone help me to write a query to fetch the rows where Email_ID not in the format of Firstname.Lastname#abc.com in the below scenario.
TABLE
S.no Firstname Lastname Email_ID
701 Sean Paul Sean.Paul#abc.com
702 Mike Tyson Mike.Samuel#abc.com
703 Richard Bernard Jim.Anderson#abc.com
704 Simon Sharma Rita.sharma#abc.com
You mean something like:
select -- some columns
from table
where Email_ID <> (FirstName + '.' + Lastname + '#abc.com')
?
There is nothing in SQL to prevent comparing one column with another, and – with a little more syntax – even across rows.
Search for rows where mail address not like Concat( firstname . lastname #)
select * from tablename
where Email_ID NOT LIKE (Firstname + '.' + Lastname + '#%')
SELECT *
FROM YourTable
WHERE CHARINDEX(FirstName + '.' + LastName + '#', Email) = 0

Splitting a Column into various columns

-- Create table dbo.FullNameTest
IF OBJECT_ID('FullNameTest') IS NOT NULL BEGIN
DROP TABLE dbo.FullNameTest;
END;
CREATE TABLE FullNameTest
(
ID INT Not Null IDENTITY
, FullName NVARCHAR(80) Not Null
, CONSTRAINT PK_ID PRIMARY KEY CLUSTERED(ID)
);
GO
INSERT INTO FullNameTest
VALUES('Mr Hog Finn Gad'), ('Grace Bruce'), ('Dr.Paul'), ('Master Clark James'), ('Mrs.Rignald')
SELECT * FROM FullNameTest
Rules
Treat entries (Mrs, Mr, Miss etc) as Titles and ignore the dot after title
When we have title and a single name, return it as Title, LastName
When we have title and two names return it as Title, FirstName and LastName
When we have title and three names, return Title, FirstName and treat the rest as LastName
When we have no title, reurn data as FirstName, LastName
No function required.
So we can get values in this form:
Title FirstName LastName
------------------------------
Mr Hog Finn Gad
Null Grace Bruce
Dr Null Paul
Master Clark James
Mrs Null Rignald
Thank you
EDIT: ***To test the results yourself, use the following to create your full name table, then run the code to create the title table, and then run the solution code below that. The results are exactly what you asked for.
CREATE TABLE #FullNameTest
(
ID INT Not Null IDENTITY
, FullName NVARCHAR(80) Not Null
);
GO
INSERT INTO #FullNameTest
VALUES('Mr Hog Finn Gad'), ('Grace Bruce'), ('Dr.Paul'), ('Master Clark James'), ('Mrs.Rignald')
This may not work in every situation, and it requires the use of a reference table with Titles, but it should get you started. Again, I would suggest putting in some data validation restraints so you don't get unexpected input. If that's not possible, then run some algorithms to clean your data first. It gets messy when you try to do stuff like this in SQL.
Create a title reference table with title and length of title.
create table #title (Title varchar(15), Long as len(Title))
insert into #title (Title) values
('Mr'),
('Mister'),
('Ms'),
('Miss'),
('Mrs'),
('Misses'),
('Dr'),
('Doctor'),
('Senator'),
('Officer'),
('Master')
Your table looks like this:
Mr 2
Mister 6
Ms 2
Miss 4
Mrs 3
Misses 6
Dr 2
Doctor 6
Senator 7
Officer 7
Master 6
Then you've got this monstrous block of code that attempts to account for every case of input you may have. AGAIN - Try to clean your data first if possible. Otherwise you will have to modify this code every time you receive something unexpected.
select y.RawName
, y.Title
, y.FName
, case when RawName like '%'+y.Title+'% %'+y.FName+'%' then RIGHT(RawName, len(RawName)-LEN(y.Title+'% %'+y.FName+' ')+1)
when Title is not null then RIGHT(RawName, len(RawName)-len(title))
when Title is null and RawName like '% %' then RIGHT(RawName, len(RawName)-len(Fname)-1)
end LName
from (
select RawName
, Title
, case when right(RawName, len(RawName)-len(title)-1) like '% %'
then left(right(RawName, len(RawName)-len(title)-1), CHARINDEX(' ', right(RawName, len(RawName)-len(title)-1),1))
when RawName like '% %'
then left(RawName, CHARINDEX(' ', RawName, 1))
end FName
from (
select
replace(f.FullName, '.', '') RawName
, t.title Title
, ROW_NUMBER() over(partition by f.fullname order by len(t.title) desc) row_n
from #FullNameTest f
left join #title t
on left(f.fullname, t.long) = t.title
) x
where row_n = 1
) y
Based on your samples from above, you are left with the following:
RawName Title FName LName
DrPaul Dr NULL Paul
Grace Bruce NULL Grace Bruce
Master Clark James Master Clark James
Mr Hog Finn Gad Mr Hog Finn Gad
MrsRignald Mrs NULL Rignald
If this is helps you with your problem, please accept it as the answer. :)
Below is the code I eventually used:
SELECT Title,
CASE
WHEN CHARINDEX(' ',PARTNAME) = 0 THEN NULL
ELSE LEFT(PARTNAME, CHARINDEX(' ',PARTNAME))
END AS [FirstName],
CASE WHEN CHARINDEX(' ',PARTNAME) = 0 THEN PARTNAME
ELSE RIGHT(PARTNAME, LEN(PARTNAME) - CHARINDEX(' ', PARTNAME))
END AS [LastName]
FROM
(
SELECT TITLE, LTRIM(REPLACE(REPLACE(FULLNAME,ISNULL(TITLE,''),''),'.','')) AS PARTNAME
FROM (
SELECT CASE
WHEN CHARINDEX('DR ',FullName) = 1 THEN 'Dr'
WHEN CHARINDEX('DR.',FullName) = 1 THEN 'Dr'
WHEN CHARINDEX('MR ',FullName) = 1 THEN 'Mr'
WHEN CHARINDEX('MR.',FullName) = 1 THEN 'Mr'
WHEN CHARINDEX('MRS ',FullName) = 1 THEN 'Mrs'
WHEN CHARINDEX('MRS.',FullName) = 1 THEN 'Mrs'
WHEN CHARINDEX('MISS ',FullName) = 1 THEN 'Miss'
WHEN CHARINDEX('MISS.',FullName) = 1 THEN 'Miss'
WHEN CHARINDEX('MASTER ',FullName) = 1 THEN 'Master'
WHEN CHARINDEX('MASTER.',FullName) = 1 THEN 'Master'
ELSE NULL
END AS [Title], FullName
FROM FullNameTest
) B
) C
Thanks so much for your help

Trouble combining rows into one column using CAST(

Ok SO, here's your time to shine!
No really, I'm getting my butt kicked by an MS-SQL query that I can't seem to get to work.
What I am trying to do is search on a patient name; but also return patients who have a similar first or last name to the querying patient's last name. So "John Smith" can return anyone named "John Smith" or anyone who has a first or last name like "smith". If the a patient has multiple disease states, then combine those disease states into a single column. I have the following tables (though of course there are many more columns, but these are the most imortant):
Patient Table
PatientID FirstName LastName UserIDFK
10000 John Smith 1
10001 Miss Smith 2
10002 Smith Bomb 3
10003 Bobby Smith 4
-- etc
DiseaseStateForUser
UserIDFK DiseaseStateRefId
1 1
1 2
2 2
3 1
3 2
4 1
GlobalLookUp
RefId Ref_Code
1 HIV
2 HEPC
The results I'm looking for are this:
PatientID FirstName LastName DiseaseStates
10000 John Smith HIV|HEPC
10001 Miss Smith HEPC
10002 Smith Bomb HIV|HEPC
10003 Bobby Smith HIV
I've taken the examples from these questions (and countless others):
Is there a way to create a SQL Server function to “join” multiple
rows from a subquery into a single delimited
field?
Simulating group_concat MySQL function in MS SQL Server
2005?
As well as from this blog post Emulating MySQL’s GROUP_CONCAT() Function in SQL Server 2005 I came up with the following SQL procedure
DECLARE
#PatientID INT=null,
#FirstName Varchar(15)= null,
#LastName Varchar(15)= 'Smith',
#Name Varchar(15) = 'John Smith',
Select
Patient.First_Name,
Patient.Last_Name,
patient.PatientID,
(select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX))
from
TBL_PATIENT patient
,TBL_GBLLOOKUP GlobalLookUp
,TBL_DiseaseStateForUser DiseaseStateForUser
-- Try and make a collection of all the PatientIDs
-- that match the search criteria
-- so that only these are used to build
-- the DiseaseStatesColumn
,(Select
Patient.PatientID
FROM TBL_PATIENT patient
,TBL_SITEMASTER SiteMaster
,TBL_USERMASTER UserMaster
,TBL_USERSINSITES UserInSites
,TBL_GBLLOOKUP GlobalLookUp
,TBL_DiseaseStateForUser DiseaseStateForUser
WHERE (((patient.[Last_Name] like #LastName + '%') OR (patient.[Last_Name] Like #Name + '%' ))
OR ((patient.[First_Name] Like #Name + '%' ))
OR (patient.[First_Name] + ' ' + patient.[Last_Name] Like #Name + '%' ))
AND UserMaster.User_Id = UserInSites.User_Id_FK
AND UserInSites.Site_Id_FK = SiteMaster.Site_Id
AND UserInSites.Is_Active = 'True'
AND patient.[User_Id_FK] = UserMaster.[User_Id]
AND (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
and DiseaseStateForUser.Is_Active='True'
AND patient.[Is_Active] = 'TRUE'
group by Patient.PatientID) as PATIENTIDs
where patient.PatientID = PATIENTIDs.PatientID
AND (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
For XML PATH('')) as MultiDiseaseState
FROM TBL_PATIENT patient, TBL_SITEMASTER SiteMaster ,TBL_USERMASTER UserMaster,TBL_USERSINSITES UserInSites, TBL_GBLLOOKUP GlobalLookUp, TBL_DiseaseStateForUser DiseaseStateForUser
WHERE (((patient.[Last_Name] like #LastName + '%') OR (patient.[Last_Name] Like #Name + '%' ))
or ((patient.[First_Name] Like #Name + '%' ))
OR (patient.[First_Name] + ' ' + patient.[Last_Name] Like #Name + '%' ))
AND patient.PatientID = patient.PatientID
AND UserMaster.User_Id = UserInSites.User_Id_FK
AND UserInSites.Site_Id_FK = SiteMaster.Site_Id
AND UserInSites.Is_Active = 'True'
AND patient.[User_Id_FK] = UserMaster.[User_Id]
AND DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id
and DiseaseStateForUser.Is_Active='True'
AND patient.[Is_Active] = 'TRUE'
group by PatientID, patient.First_Name, patient.Last_Name, GlobalLookUp.Ref_Code
order by PatientID
Unfortunately, this query nets me the following:
PatientID FirstName LastName MultiDiseaseState
10000 John Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
10001 Miss Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
10002 Smith Bomb HIV|HEPC|HEPC|HIV|HEPC|HIV
10003 Bobby Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
In other words, the select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX)) call is building up the MultiDiseaseState column with all of the disease states for ALL of the selected patients.
I know there is something fundamentally wrong with the most inner SELECT statement, but I'm having a hard time figuring out what it is and how to write the query so that it builds only the disease states for a given patient.
Kind of a long post, but are there any suggestions people can make given the code snippets I've provided?
You should be able to use the Stuff function (I think it's only on SQL 2005 and higher) to make this work, I took your example data and wrote a demonstration off of that
SET NOCOUNT ON
CREATE TABLE #Patient
(
PatientID INT,
FirstName varchar(25),
LastName varchar(25),
UserIDFK INT
)
INSERT INTO #PATIENT SELECT 10000,'John','Smith',1
INSERT INTO #PATIENT SELECT 10001,'Miss','Smith',2
INSERT INTO #PATIENT SELECT 10002,'Smith','Bomb',3
INSERT INTO #PATIENT SELECT 10003,'Bobby','Smith',4
CREATE TABLE #DiseaseStateForUser
(
UserIDFK int,
DiseaseStateRefId int
)
INSERT INTO #DiseaseStateForUser SELECT 1,1
INSERT INTO #DiseaseStateForUser SELECT 1,2
INSERT INTO #DiseaseStateForUser SELECT 2,2
INSERT INTO #DiseaseStateForUser SELECT 3,1
INSERT INTO #DiseaseStateForUser SELECT 3,2
INSERT INTO #DiseaseStateForUser SELECT 4,1
CREATE TABLE #GlobalLookUp
(
RefId int,
Ref_Code varchar(10)
)
INSERT INTO #GlobalLookUp SELECT 1,'HIV'
INSERT INTO #GlobalLookUp SELECT 2,'HEPC'
SELECT
PatientID,
UserIDFK,
FirstName,
LastName,
STUFF(
(SELECT '|' + l.Ref_Code
FROM #DiseaseStateForUser u with (Nolock)
JOIN dbo.#GlobalLookUp l with (nolock)
ON u.DiseaseStateRefId = l.RefId
WHERE u.UserIDFK = p.UserIDFK FOR XML PATH('')
)
, 1, 1, '')
FROM #PATIENT p with (Nolock)
GROUP BY PatientID, FirstName, LastName, UserIDFK

How do I perform a GROUP BY on an aliased column in SQL Server?

I'm trying to perform a group by action on an aliased column (example below) but can't determine the proper syntax.
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY 'FullName'
What is the correct syntax?
Extending the question further (I had not expected the answers I had received) would the solution still apply for a CASEed aliased column?
SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM customers
GROUP BY
LastName, FirstName
And the answer is yes it does still apply.
You pass the expression you want to group by rather than the alias
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
This is what I do.
SELECT FullName
FROM
(
SELECT LastName + ', ' + FirstName AS FullName
FROM customers
) as sub
GROUP BY FullName
This technique applies in a straightforward way to your "edit" scenario:
SELECT FullName
FROM
(
SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS FullName
FROM customers
) as sub
GROUP BY FullName
Unfortunately you can't reference your alias in the GROUP BY statement, you'll have to write the logic again, amazing as that seems.
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
Alternately you could put the select into a subselect or common table expression, after which you could group on the column name (no longer an alias.)
Sorry, this is not possible with MS SQL Server (possible though with PostgreSQL):
select lastname + ', ' + firstname as fullname
from person
group by fullname
Otherwise just use this:
select x.fullname
from
(
select lastname + ', ' + firstname as fullname
from person
) as x
group by x.fullname
Or this:
select lastname + ', ' + firstname as fullname
from person
group by lastname, firstname -- no need to put the ', '
The above query is faster, groups the fields first, then compute those fields.
The following query is slower (it tries to compute first the select expression, then it groups the records based on that computation).
select lastname + ', ' + firstname as fullname
from person
group by lastname + ', ' + firstname
Given your edited problem description, I'd suggest using COALESCE() instead of that unwieldy CASE expression:
SELECT FullName
FROM (
SELECT COALESCE(LastName+', '+FirstName, FirstName) AS FullName
FROM customers
) c
GROUP BY FullName;
My guess is:
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
Oracle has a similar limitation, which is annoying. I'm curious if there exists a better solution.
To answer the second half of the question, this limitation applies to more complex expressions such as your case statement as well. The best suggestion I've seen it to use a sub-select to name the complex expression.
You can use CROSS APPLY to create an alias and use it in the GROUP BY clause, like so:
SELECT FullName
FROM Customers
CROSS APPLY (SELECT LastName + ', ' + FirstName AS FullName) Alias
GROUP BY FullName
SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM
customers
GROUP BY
LastName,
FirstName
This works because the formula you use (the CASE statement) can never give the same answer for two different inputs.
This is not the case if you used something like:
LEFT(FirstName, 1) + ' ' + LastName
In such a case "James Taylor" and "John Taylor" would both result in "J Taylor".
If you wanted your output to have "J Taylor" twice (one for each person):
GROUP BY LastName, FirstName
If, however, you wanted just one row of "J Taylor" you'd want:
GROUP BY LastName, LEFT(FirstName, 1)
If you want to avoid the mess of the case statement being in your query twice, you may want to place it in a User-Defined-Function.
Sorry, but SQL Server would not render the dataset before the Group By clause so the column alias is not available. You could use it in the Order By.
In the old FoxPro (I haven't used it since version 2.5), you could write something like this:
SELECT LastName + ', ' + FirstName AS 'FullName', Birthday, Title
FROM customers
GROUP BY 1,3,2
I really liked that syntax. Why isn't it implemented anywhere else? It's a nice shortcut, but I assume it causes other problems?
SELECT
CASE WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM customers GROUP BY 1`
For anyone who finds themselves with the following problem (grouping by ensuring zero and null values are treated as equals)...
SELECT AccountNumber, Amount AS MyAlias
FROM Transactions
GROUP BY AccountNumber, ISNULL(Amount, 0)
(I.e. SQL Server complains that you haven't included the field Amount in your Group By or aggregate function)
...remember to place the exact same function in your SELECT...
SELECT AccountNumber, ISNULL(Amount, 0) AS MyAlias
FROM Transactions
GROUP BY AccountNumber, ISNULL(Amount, 0)