TSQL: Find part of string based on a column in temp table - sql

I need to extract the school name from a file name string. I put all of the schools in a temp table and I need to use the temp table column of SchoolName to search the string. This filename is inherited and should be a one time event to try to extract data from.
The SchoolCode and SchoolName are in the temp table. If the SchoolName matches what's in the temp table, I would like the SchoolCode as well.
I tried doing a subquery in the WHERE clause but I get an error stating it returned more than one result.
Current data:
Desired Result:
Test Code:
DROP TABLE #SchoolName
GO
CREATE TABLE #SchoolName (
FILENAME VARCHAR(MAX)
)
INSERT INTO #SchoolName
( FILENAME )
VALUES
('New Student added 10-02-16\High School\2015\North Side HS\JONES, JIMMY E_07-29-1993_2314687.PDF')
,('2006\South Side HIGH SCHOOL\GRADUATE\Johnson Jack B,03-19-1989,7123444.PDF')
,('2010\Riverwood\GRADUATES\Harmon, Kardon C_07-21-1991_370143.PDF')
,('2009\RockCreek\GRADUATES\Vandolay, Art E_09-23-1974_7210122.PDF')
DROP TABLE #SchoolsList
CREATE TABLE #SchoolsList (
SchoolCode VARCHAR(4)
,School varchar(500)
)
INSERT INTO #SchoolsList
(
SchoolCode
, School
)
VALUES
(1111 ,'North Side '),(1112 ,'South Side '),(1113 ,'Riverwood '),(1114 ,'RockCreek')

You can join to your SchoolList table using a like (assuming your school list is actually a distinct list)
SELECT l.SchoolCode, n.*
FROM #SchoolName n
LEFT OUTER JOIN #SchoolsList l
ON n.FILENAME LIKE '%' + l.School + '%'
Riverwood doesn't return a code since you have a space in the school list (SS and NS work since there is actually a space after them in both the filename and the school list)

I think you're looking for
SELECT SL.*
FROM SchoolsList SL JOIN SchoolName SN
ON SN.FileName LIKE CONCAT('%\', RTRIM(LTRIM(SL.School)), '%');
-- You can remove LTRIM() if there is no spaces in the begining
Demo

Related

Combine Multiple Rows Into A Single Column

I am working on a stored procedure for reporting purposes and I need to combine rows in a single column but I can't find a way to do this. I have four tables, Case, Debtor, DebtorAddress and CaseNote. Rather than try to do this in a single statement I decided to create a temp table with the columns needed, populate the ones that occupy a single row, then use an update statement to combine the multiple rows of the last column needed into a single row. My temp table has rows for CApKey (the ID of the Case table), OwnerName (from Debtor), Address (from DebtorAddress, and Note. For each Case there may be multiple Notes (stored in the CaseNote table). So I may have Case #1, with a CApKey value of 1, OwerName of John Jones, Address of 1234 Main St. There may be one Note the says 'Called and left message', another that says 'Sent letter', and another that says 'Left a second voicemail', etc. I'd like to combine the three notes into a single row with Note values of Called and left a message, Sent Letter, and Left a second voicemail. I can use space, period, or comma as a delimiter. I found a way to do the update in theory but I'm getting an error that the sub-query returned more than 1 value. Below is the "heart" of the procedure. I've been wracking my brain on this for two days now. Any assistance is greatly appreciated in advance. Here is the statement I'm trying:
CREATE TABLE #temp
(
CaseKey int,
OwnerName varchar(500),
Address varchar(500),
Note varchar(MAX)
)
DECLARE #val Varchar(MAX);
INSERT INTO #temp
(CaseKey, OwnerName, Address)
SELECT ca.CApKey, DEFirstName + ' ' + DELastName, da.DAAddress1
FROM [Case] ca INNER JOIN Debtor de ON ca.CApKey = de.CApKey INNER JOIN DebtorAddress da ON ca.CApKey = da.CApKey
WHERE ca.LFpKey = #LFpKey AND de.DEIsPrimary = 1
UPDATE #temp SET Note =
(SELECT COALESCE(#val + ', ' + CANNote, CANNote)
FROM CaseNote WHERE CApKey = 51)
--SELECT #val;)
SELECT * FROM #temp
Thanks!
If i understood you correctly, you need to combine all the notes.
Get your data, queried from the 4 tables into a table (ex. #t)
Then you can use XML PATH and Stuff to achieve your goal (later you can use that for whatever your purpose as inserting to a table or display in a report etc)
SELECT CaseKey, OwnerName, Address, (STUFF((
SELECT ', ' + Note
FROM #t tx
where tx.CaseKey = t.CaseKey and tx.OwnerName = t.OwnerName and tx.Address = t.Address
FOR XML PATH('')
), 1, 2, '')
) AS StringValue
From #t t
Group by CaseKey, OwnerName, Address
Here is the fiddle

SQL select specific letter from concatenated string

This may have been answered similarly somewhere but I am still kind of confused. I need to create a view named A7T7 that will display the concatenated first name and last name of the students who have at least three letter Os or three letter Ts in their concatenated name (e.g., John Olson, Richard Hooton, Tina Trout). The column heading should be Student and the rows should be sorted by the length of the concatenated names from long to short.
Not really sure how to make my WHERE statement for this restriction.
You can use a LIKE query - for example (using a table variable for SQL Server):
CREATE TABLE #students (firstname varchar(20), lastname varchar(20));
INSERT ALL
INTO #students VALUES ('John','Olson')
INTO #students VALUES ('Richard','Hooton')
INTO #students VALUES ('Tina','Trout')
SELECT 1 FROM dual;
SELECT *
FROM #students s
WHERE CONCAT(s.firstname, s.lastname) LIKE '%o%o%o%';
DROP TABLE #students;
Which roughly translates to "select all the rows from students where the concatenation of firstname and lastname contains o three times".

SQL query with pivot tables?

I'm trying to wrap by brain around how to use pivot tables for a query I need. I have 3 database tables. Showing relevant columns:
TableA: Columns = pName
TableB: Columns = GroupName, GroupID
TableC: Columns = pName, GroupID
TableA contains a list of names (John, Joe, Jack, Jane)
TableB contains a list of groups with an ID#. (Soccer|1, Hockey|2, Basketball|3)
TableC contains a list of the names and the group they belong to (John|1, John|3, Joe|2, Jack|1, Jack|2, Jack|3, Jane|3)
I need to create a matrix like grid view using a SQL query that would return a list of all the names from TableA (Y-axis) and a list of all the possible groups (X-axis). The cell values would be either true or false if they belong to the group.
Any help would be appreciated. I couldn't quite find an existing answer that helped.
You might try it like this
Here I set up a MCVE, please try to create this in your next question yourself...
DECLARE #Name TABLE (pName VARCHAR(100));
INSERT INTO #Name VALUES('John'),('Joe'),('Jack'),('Jane');
DECLARE #Group TABLE(gName VARCHAR(100),gID INT);
INSERT INTO #Group VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
DECLARE #map TABLE(pName VARCHAR(100),gID INT);
INSERT INTO #map VALUES
('John',1),('John',3)
,('Joe',2)
,('Jack',1),('Jack',2),('Jack',3)
,('Jane',3);
This quer will collect the values and perform PIVOT
SELECT p.*
FROM
(
SELECT n.pName
,g.gName
,'x' AS IsInGroup
FROM #map AS m
INNER JOIN #Name AS n ON m.pName=n.pName
INNER JOIN #Group AS g ON m.gID=g.gID
) AS x
PIVOT
(
MAX(IsInGroup) FOR gName IN(Soccer,Hockey,Basketball)
) as p
This is the result.
pName Soccer Hockey Basketball
Jack x x x
Jane NULL NULL x
Joe NULL x NULL
John x NULL x
Some hints:
You might use 1 and 0 instead of x as SQL Server does not know a real boolean
You should add a pID to your names. Never join tables on real data (unless it is something unique and unchangeable [which means never acutally!!!])
UPDATE dynamic SQL (thx to #djlauk)
If you want a query which deals with any amount of groups you have to to this dynamically. But please be aware, that you loose the chance to use this in ad-hoc-SQL like in VIEW or inline TVF, which is quite a big backdraw...
CREATE TABLE #Name(pName VARCHAR(100));
INSERT INTO #Name VALUES('John'),('Joe'),('Jack'),('Jane');
CREATE TABLE #Group(gName VARCHAR(100),gID INT);
INSERT INTO #Group VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
CREATE TABLE #map(pName VARCHAR(100),gID INT);
INSERT INTO #map VALUES
('John',1),('John',3)
,('Joe',2)
,('Jack',1),('Jack',2),('Jack',3)
,('Jane',3);
DECLARE #ListOfGroups VARCHAR(MAX)=
(
STUFF
(
(
SELECT DISTINCT ',' + QUOTENAME(gName)
FROM #Group
FOR XML PATH('')
),1,1,''
)
);
DECLARE #sql VARCHAR(MAX)=
(
'SELECT p.*
FROM
(
SELECT n.pName
,g.gName
,''x'' AS IsInGroup
FROM #map AS m
INNER JOIN #Name AS n ON m.pName=n.pName
INNER JOIN #Group AS g ON m.gID=g.gID
) AS x
PIVOT
(
MAX(IsInGroup) FOR gName IN(' + #ListOfGroups + ')
) as p');
EXEC(#sql);
GO
DROP TABLE #map;
DROP TABLE #Group;
DROP TABLE #Name;
I suspect it may be laborious to keep the pivot up to date if categories are added. Or maybe I just prefer Excel (if you ignore one major advantage). The following approach could be helpful too, assuming you do have Office 365.
I added the three tables using 3 CREATE TABLE statements and 3 INSERT statements based on the code I saw above. (The solutions make use of temporary tables to insert specific values, but I believe you already have the data in your three tables, called TableA, TableB, TableC).
CREATE TABLE TestName (pName VARCHAR(100));
INSERT INTO TestName VALUES('John'),('Joe'),('Jack'),('Jane');
CREATE TABLE TestGroup (gName VARCHAR(100),gID INT);
INSERT INTO TestGroup VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
CREATE TABLE Testmap (pName VARCHAR(100),gID INT);
INSERT INTO Testmap VALUES
('John',1),('John',3)
,('Joe',2)
,('Jack',1),('Jack',2),('Jack',3)
,('Jane',3);
Then, in MS Excel, I added (there may be a shorter sequence but I'm still exploring) the three tables as queries from database > sql server database. After adding them, I added all three to the Data Model (I can elaborate if you ask).
I then inserted PivotTable from the ribbon, chose External data source, but opened the Tables tab (instead of Connections tab), to find my data model (mine was top of the list) and I clicked Open. At some point Excel prompted me to create relationships between tables and it did a good job of auto generating them for me.
After minor tweaks my PivotTable came out like this (I could also ask Excel to show the data as a PivotChart).
Pivot showing groups as columns and names as rows.
The advantage is that you don't have to revisit the PIVOT code in SQL if the list (of groups) changes. As I think someone else mentioned, consider using ids for pName as well, or another way to ensure that you are not stuck the next day if you have two persons named John or Jack.
In Excel you can choose when to refresh the data (or the pivot) and, after refresh, any additional categories will be added and counted.

sql concat within a SELECT statement

This is similiar to this one. How to concatenate all columns in a select with SQL Server
But not quite. This is MS SQL 2008. I am pulling patient demographics, and one of those is race, which is a multi-choice field (you could be asian and chinese for example). The race table 'PatientRace' is linked to the patient table by patientid. So the table structure is thus:
Patient table
PatientID
PatientName
PatientAddress
PatientRace table
PatientRaceID
PatientID (FK)
Description
I only want one row, and I want race to be concatenated. Is it possible to do this within a single SELECT statement or do I need to do a cursor? I am envisioning the cursor to be like this: Initial select for all the other demographics, insert into a temp table. Go through the temp table by patientID, then for each, grab out the race, concat, and add to the temp table.
The desired output is like this: 1 row per patient.
Name: "Joe Blow"
Race: "Asian, Chinese"
You need to use STUFF and FOR XML like this
SELECT p.PatientName,
(STUFF(SELECT ',' + r.Description
FROM PatientRace r
WHERE r.PatientID = p.PatientID
FOR XML('')), 1, 1, '')
FROM Patients p
Concatenating string values in SQL Server is not obvious. It requires using "xml" data processing and a subquery:
select p.*,
stuff((select ', ' + Description
from patientrace pr
where pr.patientid = p.patientid
for xml path ('')
), 1, 2, ''
) as races
from patients p;
As for me, you have write function like fn_GetRaceByID(int PatientID), that returns desired string. So use it in your select. Link in your question has good example, how to do this.

SQL query to fillter and update table

i have an employee database table with a column NAME
in the NAME field we have names of employees like this -> LI-MING (ALLEN)
this is there real first name and there English nick name in ()
i would like to know if i can swap this around in an SQL UPDATE query
FROM: LI-MING (ALLEN) TO: ALLEN (LI-MING)
the reason why i would like this is Users want to have it sort this column by nick name
Try this
UPDATE Employee
SET NAME =
SUBSTRING(name,CHARINDEX('(',name)+1,(CHARINDEX(')',name)-CHARINDEX('(',name)-1))+
' ('+SUBSTRING(name,1,CHARINDEX('(',name)-1)+')'
FROM Employee
If I were you I would create seperate colums both for name and nick name. Trying to get a string portion on the fly prevent sql server from using indexes which might be really importand from performance perspective.
So there are basicly two options:
Parse values for seperate columns every time you update or insert a new employee (via TRIGGER, application code, etc).
Or just create two calculated columns but make sure they are marked as PERSISTED.
Hope it helps!
I had worked on several project and I have done it my way to update same issue that you been through in 3 steps:
1) Create table with ID or Name field and Insert the values to the table
2) Trim the values with different functions and insert the final value to different table.
3) Update the old table with the new value
I don't say this is the only way to do thing but there might be other ways as well.
Create table #Employee(
EmployeeName varchar(200)
)
Insert into #Employee
Select 'LI-MING (ALLEN)' union all
Select 'Jio-Kio (Smith)'
Select
substring(employeename,1,patindex('%(%',employeename)-1),
--Len(substring(employeename,1,patindex('%(%',employeename)-1)),
Right(employeename,len(employeename)-(len(substring(employeename,1,patindex('%(%',employeename)))))
from #Employee
Create table #EmployeeNew(
Employeename1 varchar(200),
Employeename2 varchar(200)
)
Insert into #EmployeeNew(Employeename1, Employeename2)
Select
ltrim(rtrim(substring(employeename,1,patindex('%(%',employeename)-1))),
ltrim(rtrim(Right(Employeename,charindex('(',employeename,1)-3)))
from #Employee
Select * from #Employee
Select * from #EmployeeNew
Select cast('('+Employeename1+')'+left(employeename2,len(employeename2)-1) as varchar(200)) from #EmployeeNew
Update e
Set e.EmployeeName = cast('('+e1.Employeename1+')'+left(e1.employeename2,len(e1.employeename2)-1) as varchar(200))
from #Employee e
left outer join #EmployeeNew e1 on ltrim(rtrim(substring(e.employeename,1,patindex('%(%',e.employeename)-1))) =e1.Employeename1