T-SQL Case statement where value is derived from joining tables - sql

I have the following simple query (sql server 2012)
SELECT T.[taskId], T.[sectionId], T.[DateAdded]
FROM [TASK] AS T
WHERE (T.[deleted] = 0)
ORDER BY T.[DateAdded]
What I would like to do is create a computed column called type, which will be 1 if SectionId is null. If not null this will contain a foreign key for a table called Organisation. Organisation has a column called type. If the type of the joined row in organisation is 6 then my computed type value should be 2, else it will be 3.
I'm guessing a CASE would be ideal for this but I', not exactly sure how to go about it.

To project a derived column, add a join to your organisation table and derive the new column based on the various values:
SELECT T.[taskId], T.[sectionId], T.[DateAdded],
CASE
WHEN SectionId IS NULL THEN 1
WHEN o.[type] = 6 THEN 2
ELSE 3
END AS [type]
FROM [TASK] AS T
-- Applicable join condition goes here ...
LEFT OUTER JOIN Organisation o ON t.TaskID = o.TaskID
WHERE (T.[deleted] = 0)
ORDER BY T.[DateAdded]
If you **literally** want a computed column, it will look something like this:
ALTER TABLE TASK ADD [Type] AS
CASE
WHEN SectionId IS NULL THEN 1
WHEN (SELECT [type] FROM Organisation WHERE ... JOIN KEY) = 6 THEN 2
ELSE 3
END;

Related

SQL join based on select as column name

So in one table I can use a replace and charindex to extract a specific ID that relates to a PK in another table, I want to then join the data from the other table based on the trimmed value, how can I do this?
select top 100 *, Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID, PrmRoutingTask.*
from SytLog
inner join PrmRoutingTask on RtaId = TaskID
where LogTableName like '%Routing%' and LogValue like '%RtaAniId=397%'
order by 5 desc;
The problem I get is that the temp column name I create (TaskID) is not working in the inner join where in fact the results of TaskID have the reference to the RtaId in the RoutingTask table.
Assuming LogValue belongs to the first table you can use the column named TaskID if you produce a subquery as a table expression of the main query.
For example you can produce the column in the table expression a by doing:
select top 100
a.*,
PrmRoutingTask.*
from (
select *,
Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID
from SytLog
) a
inner join PrmRoutingTask on PrmRoutingTask.RtaId = a.TaskID
where LogTableName like '%Routing%'
and LogValue like '%RtaAniId=397%'
order by 5 desc

Microsoft SQL query multiple condition

I have an Attributes table which has a set of attributes identified by a unique number and then followed by their description - An example schema is
ID - AttributeName
with some sample data below
1 = FirstName
2 = LastName
3 = Phone
I then have an employees table which for the sake of simplicity has the following schema
ID - PersonID
AttribueID - INT Foreign key to the above attributes table
I need to create a stored proc that given a condition will return records based on one of the following conditions
If I pass in a 1 to the stored procedure the proc should return all records from the Person table who match the attribute ID 1 (First name)
If I pass in a 2 to the stored procedure the proc should return all records from the Person table who * DO NOT * match the attribute ID 1 (First name)
If I pass in a 3 to the stored procedure the proc should return all records from the Person table
I could do the following but feel it is not the best way this could be performed
DECLARE #IntID INT = 1 -- Set as 1 just for exmple
IF #IntID =1
BEGIN
SELECT * FROM Person where AttributeID IN (SELECT ID from Attributes Where ID =1) -- match on attribute 1
END
ELSE IF #IntID = 2
BEGIN
SELECT * FROM Person where AttributeID NOT IN (SELECT ID from Attributes Where ID =1) -- do not match on attribute 1
END
ELSE
BEGIN
SELECT * FROM Person where AttributeID IN (SELECT ID from Attributes) -- return match on all attributes
END
The above example has an extremely simple SELECT statement - in the real SQL there is a much larger set
Thanks in advance
If you don't wanna use dynamic sql then you may try this. And your query is too simple that for performance optimization, you may look to the table indexes for that.
DECLARE #IntID INT = 1 -- Set as 1 just for exmple
IF #IntID = 1 OR #IntID = 2
BEGIN
SELECT A.*
FROM Person A
LEFT JOIN Attributes B ON A.AttributeID = B.ID AND B.ID = 1
WHERE
A.AttributeID IS CASE #IntID WHEN 1 THEN NOT NULL WHEN 2 THEN NULL END
END
ELSE
BEGIN
SELECT A.*
FROM Person A
INNER JOIN Attributes B ON A.AttributeID = B.ID
END

SQL Update IDs for columns in the same table

I'm sure this is answered elsewhere, however I'm not sure how to search for this specific question.
Let's say I have 2 tables:
InputDataNames with columns [Prospect_Name], [Product_Name], [Market_Name]
Entity with columns [EntityId], [Name], [EntityTypeId], where [Name] is used in the InputDataNames table.
Now suppose I want to create a table equal to InputDataNames, but instead of Names, fill in with IDs from the Entity table:
InputDataIDs with columns [Prospect_ID], [Product_ID], [Market_ID]
Using the InputDataNames table to populate the appropriate combination of IDs, how can I join with the Entity table to get the desired effect?
Note: I know this is sloppy, just doing a little database cleanup.
You can join to the entity table three times. Assuming the EntityTypeId column determines whether or not the entity is a prospect, product, or market, then you should include that column in the join. If they are numbered 1,2,3:
select
pros.entityid, prod.entityid, mkt.entityid
from
inputdatanames id
inner join
entity pros on id.prospect_name = pros.name and pros.entitytypeid = 1
inner join
entity prod on id.product_name = prod.name and prod.entitytypeid = 2
inner join
entity mkt on id.market_name = mkt.name and mkt.entitytypeid = 3
insert InputDataIDs
(Prospect_ID, Product_ID, Market_ID)
select Prospect.EntityID
, Product.EntityID
, Market.EntityID
from InputDataNames
left join
Entity Prospect
on Prospect.EntityTypeId = 1 -- Type of prospect
and Prospect.Name = InputDataNames.Prospect_Name
left join
Entity Product
on Product.EntityTypeId = 2 -- Type of product
and Product.Name = InputDataNames.Product_Name
left join
Entity Market
on Market.EntityTypeId = 3 -- Type of market
and Market.Name = InputDataNames.Market_Name

SQL Server Compare two rows to identify ID

Here is what I am trying to do.
I have one column of data that is the ID of every person. I have a second column of data that is the ID of just supervisors. I also have a third column of data that identifies an ID as staff or faculty.
I need to take the Supervisor column and compare it against the ID column. When the supervisor's ID is located then I need to identify that row as a staff of faculty supervisor in a separate column. If the ID is not in the supervisor column then they just need to be marked as staff or faculty based off of the third column.
So the three columns that I have are ID, Supervisor ID and Class Type.
Any help would be appreciated.
Here is the code that I currently have
select distinct ODS_PERSON.ID "Cient_ID",
ODS_PERSON.LAST_NAME "Last_Name",
CASE
WHEN H17_PERSON.NICKNAME is not null
THEN H17_PERSON.NICKNAME
ELSE ODS_PERSON.FIRST_NAME
END "First_Name",
H17_PERSON.H17_PER_USERNAME + '#highpoint.edu' "Email",
CASE
WHEN ODS_HRPER.HRP_EFFECT_TERM_DATE is null
THEN '1'
ELSE '0'
END "User_Status",
CASE
WHEN SPT_POSITION.POS_CLASS = 'FACL' AND (ODS_PERSON.ID = SPT_PERPOS.PERPOS_SUPERVISOR_HRP_ID)
THEN 'FACSUP'
ELSE 'NOPE'
END "Employee_Type",
SPT_PERPOS.PERPOS_SUPERVISOR_HRP_ID "Manager",
SPT_POSITION.DEPARTMENT_DESC "Department",
SPT_PERPOS.PERPOS_POS_SHORT_TITLE "Position_Title",
SPT_POSITION.POS_CLASS "Position_Class"
from ( ( ( ( ( SPT_PERPOSWG SPT_PERPOSWG left join ODS_HRPER ODS_HRPER on SPT_PERPOSWG.PPWG_HRP_ID = ODS_HRPER.HRPER_ID ) left join SPT_PERPOS SPT_PERPOS on SPT_PERPOSWG.PPWG_HRP_ID = SPT_PERPOS.PERPOS_HRP_ID ) left join SPT_PERSTAT SPT_PERSTAT on SPT_PERPOSWG.PPWG_HRP_ID = SPT_PERSTAT.PERSTAT_HRP_ID ) left join ODS_PERSON ODS_PERSON on SPT_PERPOSWG.PPWG_HRP_ID = ODS_PERSON.ID ) left join SPT_POSITION SPT_POSITION on SPT_PERPOS.PERPOS_POSITION_ID = SPT_POSITION.POSITION_ID ) left join H17_PERSON H17_PERSON on SPT_PERPOSWG.PPWG_HRP_ID = H17_PERSON.ID
where ODS_HRPER.HRP_EFFECT_TERM_DATE is null
and SPT_PERPOS.PERPOS_END_DATE is null
order by ODS_PERSON.ID
SELECT ID, Supervisor_ID, Class_Type,
CASE
WHEN SuperVisor_ID is null and Class_Type is not null THEN Class_Type
WHEN (SuperVisor_ID = ID or SuperVisor_ID is not null) THEN 'Supervisor'
END
from tableID
Not sure if this is what you're looking for. In the future it would be helpful to know how many tables are involved, and if the data types in each column can be compared directly or if you have to cast the data types.
You may also want to put whether join conditions are necessary to get the information and what columns the tables would join on.
Hope this helps

How to transform vertical table into horizontal table?

I have one table Person:
Id Name
1 Person1
2 Person2
3 Person3
And I have its child table Profile:
Id PersonId FieldName Value
1 1 Firstname Alex
2 1 Lastname Balmer
3 1 Email some_email#test.com
4 1 Phone +1 2 30004000
And I want to get data from these two tables in one row like this:
Id Name Firstname Lastname Email Phone
1 Person1 Alex Balmer some_email#test.com +1 2 30004000
What is the most optimized query to get these vertical (key, value) values in one row like this? Now I have a problem that I done four joins of child table to parent table because I need to get these four fields. Some optimization is for sure possible.
I would like to be able to modify this query in easy way when I add new field (key,value). What is the best way to do this? To create some stored procedure?
I would like to have strongly types in my DB layer (C#) and using LINQ (when programming) so it means when I add some new Key, Value pair in Profile table I would like to do minimal modifications in DB and C# if possible. Actually I am trying to get some best practices in this case.
Select
P.ID
, P.Name
, Case When C.FieldName = 'FirstName' Then C.Value Else NULL END AS FirstName
, Case When C.FieldName = 'LastName' Then C.Value Else NULL END AS LastName
, Case When C.FieldName = 'Email' Then C.Value Else NULL END AS Email
, Case When C.FieldName = 'Phone' Then C.Value Else NULL END AS Phone
From Person AS P
Inner JOIN Child AS C
ON P.ID = C.PersonID
You could use PIVOT; not sure which one would be the easiest for you to add a new column.
best optimized way with strongly typed fields, is to do it this way:
CREATE TABLE Persons
(PersonID int identity(1,1) primary key
,Firstname varchar(...)
,Lastname varchar(...)
,Email varchar(...)
,Phone varchar(...)
,....
)
then the most optimized query would be:
SELECT
PersonID,Firstname,Lastname,Email,Phone
FROM Persons
WHERE ...
Add all main columns into the persons table. if you need to specialize create additional tables:
--one person can play many instruments with this table
CREATE TABLE PersonMusicians
(PersonID int --pk fk to Persons.PersonID
,InstrumentCode char(1) --pk
,...
)
--only one row per person with this table
CREATE TABLE PersonTeachers
(PersonID int --pk fk to Persons.PersonID
,FavoriteSubjectCode char(1)
,SchoolName varchar(...)
)
if you have to have unlimited dynamic attribute fields, then I would create the above structure as fully as possible (as many common fields as possible) and then have an "AdditionalInfo" table where you store all the info like:
AdditionalInfoFields
FieldID int identity(1,1) primary key
FieldName varchar(...)
AdditionalInfo
AdditionalInfoID int identity(1,1) primary key
PersonID int fk to Persons.PersonID
FieldID int fk to AdditionalInfoFields.FieldID
FieldValue varchar(..) or you can look into sql_variant
have an index on AdditionalInfo.PersonID+FieldID and if you will search for all people that have attribute X, then also another like AdditionalInfo.FieldID+PersonID
short of any of the above, you will need to use the four left outer joins like you have mentioned in your option #1:
SELECT
P.ID, p.Name
, p1.Value AS Firstname
, p2.value AS Lastname
, p3.Value AS Email
, p4.Value AS Phone
FROM Persons p
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Firstname'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Lastname'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Email'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Phone'
WHERE ....
you could always make a materialized view with an index out of this 4 left join query and have the data precalculated for you which should speed it up.