SQL joins with mulitple where conditions - sql

I have one table that looks like this:
[Jobs]
+-----+-------+---------+
+ ID + Title + Active +
+-----+-------+---------+
+ 1 + Admin + 0 +
+-----+-------+---------+
+ 2 + Mgr + 1 +
+-----+-------+---------+
+ 3 + Emp + 0 +
+-----+-------+---------+
[JobsTxt]
+-------+-------+---------+
+ JobID + Text + Type +
+-------+-------+---------+
+ 1 + test + 1 +
+-------+-------+---------+
+ 1 + test2 + 1 +
+-------+-------+---------+
+ 1 + test3 + 2 +
+-------+-------+---------+
+ 3 + test + 1 +
+-------+-------+---------+
I want to write a query that gives me the Text entries from the JobsTxt table that have Type= 1 and Active=0 in the Jobs table, where JobsTxt.JobID = Jobs.ID
So it'd be something like:
Select [JobsTxt].Text from [JobsText] left join [Jobs] on [JobsTxt].JobId = [Jobs].ID where [JobsTxt].Type = 1 and [Jobs].Active = 0
I'm very new to joins and queries like this, so any help is appreciated!

EXISTS are good if you dont require a JOIN, meaning you only need fields from one of the tables.
SELECT jt.Text
FROM [JobsText] jt
WHERE jt.Type = 1
AND EXISTS
(
SELECT 1
FROM [Jobs] j
WHERE j.ID = jt.JobID
AND j.Active = 0
);

Please excuse, I am not allowed to comment directly on your question. So, let me just put it here, even as I think this may not qualify as an answer.
To me, your SQL statement looks perfectly okay and should deliver what you described. Maybe you could help us out and give some information on the SQL dialect involved (i.e., what database system you are running and what version)?
edit:
it seems you do have a typo:
[...] from [JobsText] [...]
↑ - should there be an 'e'?
Thank you.

Please make use of below query:
DECLARE #Jobs TABLE (ID INT, Title VARCHAR(10), Active BIT )
INSERT INTO #Jobs VALUES
(1,'Admin',0),
(2,'Mgr',1),
(3,'Emp',0)
DECLARE #Jobtxt TABLE ( JobID INT, [Text] VARCHAR(10), [Type] INT)
INSERT INTO #Jobtxt VALUES
(1,'test',1),
(1,'test2',1),
(1,'test3',2),
(3,'test',1)
SELECT
Jt.JobID,Jt.[Text]
FROM
#Jobtxt Jt INNER JOIN #Jobs J ON Jt.JobID = J.ID
WHERE
J.Active = 0 AND Jt.[Type] =1

Related

Built DWH From Father-Child table efficiently with T-SQL

For the last two days, I've been trying to find an efficient solution as most dynamic as possible but I can't make it. Do you have a hint for the following example? I tried a recursive call to get the "level" or the native join so far with the results below.
I have "initTable":
parent | child
-------+------
A | H
A | B
A | C
B | D
B | G
C | F
D | E
I want to have "finalTable": (in the bescase with dynamically create columns "levelX"
level1 | level2 | level 3 | level 4
-------+--------+---------+---------
A | A | A | H
A | A | C | F
A | A | B | G
A | B | D | E
Attempt #1: recursive way to get the level
Question: Is there a possibility to create the for each level a column during the recursion?
WITH recTable (father, child, lev) AS
(
SELECT
p1.father,
p1.child,
0 as lev
FROM
initTable AS p1
WHERE
p1.father = 'A'
UNION ALL
SELECT
p1.father,
p1.child,
lev+1
FROM
initTable AS p1
INNER JOIN
recTable as p2 ON p1.father = p2.child
)
SELECT * FROM ASD
Attempt #2: but with "wrong" order
Here I would need to fill up the columns "backwards" somehow...
SELECT
p1.child AS Level 1,
p2.child AS Level 2,
p3.child AS Level 3,
p4.child AS Level 4
FROM
initTable p1
LEFT JOIN
initTable p2 ON p1.child = p2.father
LEFT JOIN
initTable p3 ON p2.child = p3.father
LEFT JOIN
initTable p4 ON p3.child = p4.father
WHERE
p1.father= 'A'
Does someone know a nice and efficient way to solve this problem? I feel like I m pretty close but I just can't solve it so far.
The following is dynamic and will work for your example, as well as for any with more/less parent/child relationships:
-- Get the number of required fields
SELECT
parent
, child
, 1 [level]
INTO #checking
FROM initTable
WHERE parent NOT IN (SELECT child FROM initTable)
;
WHILE EXISTS (SELECT * FROM #checking c JOIN initTable t ON c.child = t.parent)
BEGIN
INSERT INTO #checking
SELECT
t.parent
, t.child
, (SELECT MAX([level]) + 1 FROM #checking)
FROM
#checking c
JOIN initTable t ON c.child = t.parent
;
DELETE
FROM #checking
WHERE [level] <> (SELECT MAX([level]) FROM #checking)
;
END
;
DECLARE #requiredLevels int = (SELECT TOP 1 [level] + 1 FROM #checking)
;
DROP TABLE #checking
;
-- Build a dynamic statement for the SELECT fields
DECLARE
#fieldSQL varchar(1000) = ''
, #fieldsN int = #requiredLevels
;
WHILE #fieldsN > 0
BEGIN
IF #fieldsN > 2
BEGIN
DECLARE
#coalesceFields varchar(1000) = ''
, #coalesceN int = #fieldsN
WHILE #coalesceN > 1
BEGIN
IF #coalesceFields = ''
SET #coalesceFields = 'L' + CAST(#coalesceN AS varchar) + '.parent'
ELSE
SET #coalesceFields = #coalesceFields + ', L' + CAST(#coalesceN AS varchar) + '.parent'
;
SET #coalesceN = #coalesceN - 1
END
SET #fieldSQL = #fieldSQL + ', COALESCE(' + #coalesceFields + ') [level ' + CAST(#requiredLevels - #fieldsN + 1 AS varchar) + ']'
END
ELSE
SET #fieldSQL = #fieldSQL + ', L' + CAST(#fieldsN AS varchar) + '.' + CASE WHEN #fieldsN = 1 THEN 'child' ELSE 'parent' END + ' [level ' + CAST(#requiredLevels - #fieldsN + 1 AS varchar) + ']'
;
SET #fieldsN = #fieldsN - 1
END
SET #fieldSQL = SUBSTRING(#fieldSQL, 3, LEN(#fieldSQL) - 2)
-- Build a dynamic statement for the LEFT JOINs
DECLARE
#joinSQL varchar(1000) = ''
, #joinsN int = 2
WHILE #joinsN <= #requiredLevels
BEGIN
SET #joinSQL = #joinSQL + ' LEFT JOIN initTable L' + CAST(#joinsN AS varchar) + ' ON L' + CAST(#joinsN - 1 AS varchar) + '.' + CASE WHEN #joinsN = 2 THEN 'child' ELSE 'parent' END + ' = L' + CAST(#joinsN AS varchar) + '.child'
SET #joinsN = #joinsN + 1
END
-- Build the final SQL statement and execute
DECLARE #SQL varchar(8000) =
'
SELECT ' + #fieldSQL + '
FROM
(
SELECT child
FROM initTable
WHERE child NOT IN (SELECT parent FROM initTable)
) L1' + #joinSQL
EXEC (#SQL)

Ordering SQL SELECT by result of a string comparison

I have a table with two string columns, ID and LANGUAGE. Language can be one of CYM, ENG, GAE.
When selecting data from the table, I want to order it by the language column, putting a specified language at the start of the results, with the other languages later, in any order.
Say I have the data
+===+=====+
+ 1 + CYM +
+ 2 + GAE +
+ 3 + ENG +
+ 4 + CYM +
+===+=====+
and I want the output to be
+===+=====+
+ 3 + ENG +
+ 1 + CYM +
+ 2 + GAE +
+ 4 + CYM +
+===+=====+
How do I do the equivalent of
SELECT ID, LANGUAGE
FROM TABLE
ORDER BY (LANGUAGE = 'ENG'), ID
You can use CASE WHEN to ensure ENG will be first:
SELECT ID, LANGUAGE
FROM your_table
ORDER BY
CASE LANGUAGE WHEN 'ENG' THEN 0
ELSE 1
END ASC;
-- ,ID ASC -- if needed
LiveDemo

Conversion failed when converting the nvarchar value '29449,29446,29450,29534' to data type int

I am create a stored procedure in SQL and I get the following error when I execute the query:
Conversion failed when converting the nvarchar value '11021,78542,12456,24521' to data type int.
Any idea why?
SELECT
A.Art_ID, A.Title
FROM
Art A
INNER JOIN
Iss I ON A.Iss_ID = I.Iss_ID
INNER JOIN
Sections S ON A.Section_ID = S.Section_ID
INNER JOIN
iPadSec IPS ON A.Sec_ID = IPS.Sec_ID
WHERE
A.Art_ID IN (SELECT CAST(Art_IDs AS int) /***error happens here***/
FROM Book_Art b
WHERE Sub_ID = 68)
AND I.Iss > dateadd(month, -13, getdate())
AND A.Active = 1
AND IPS.Active = 1
AND A.PDate <= getdate()
ORDER BY
PDate DESC, Art_ID DESC;
You cannot do what you want using in. First, it is a really bad idea to store ids in lists in strings. You should be using a junction table.
That said, sometimes this is necessary. You can rewrite this line of code as:
EXISTS (SELECT 1 /***error happens here***/
FROM Book_Art b
WHERE Sub_ID = 68 AND
',' + Art_IDs + ',' LIKE '%,' + cast(A.Art_ID as varchar(255)) + ',%'
)
However, the performance would generally be on the lousy side and there is little prospect of speeding this up without fixing the data structure. Use a junction table instead of a string to store lists.
Adding this line works for me.
declare #ids varchar(1000)
select #ids = art_ids from book_art where sub_id = #Sub_ID
EXECUTE ( 'SELECT A.Art_ID, A.Title'
+ ' FROM Art A'
+ ' INNER JOIN Iss I ON A.Iss_ID = I.Iss_ID'
+ ' INNER JOIN Sections S ON A.Section_ID = S.Section_ID'
+ ' INNER JOIN iPadSec IPS ON A.Sec_ID = IPS.Sec_ID'
+ ' WHERE A.Art_ID IN (' + #ids + ')'
+ ' AND I.Iss > dateadd(month, -13, getdate())'
+ ' AND A.Active = 1'
+ ' AND IPS.Active = 1'
+ ' AND A.PDate <= getdate()'
+ ' ORDER BY PDate DESC,'
+ ' Art_ID DESC;'
)
END
Thank you all for your help :)

SQL query returns multiple rows when trying to find specific value

I have 2 tables. One is called "Tasks" and the other one is called "TaskDescription"
in my "Task" the setup looks like this:
"taskID(primary)","FileID","TaskTypeID" and a bunch of other columns irrelevant.
Then in my "TaskDescription", the setup looks like:
"TaskTypeID", "TaskTypeDesc"
so for example if TaskTypeID is 1 , then the description would be"admin"
or if TaskTypeID is 2, then TaskTypeDesc would be "Employee" etc.
The two tables have a relationship on the primary/foreign key "TaskTypeID".
What I am trying to do is get a task id, and the TaskDesc where the FileID matches the #fileID(which I pass in as a param). However in my query I get multiple rows returned instead of a single row when trying to obtain the description.
this is my query:
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast((SELECT DISTINCT td.tasktypedesc FROM casefiletaskdescriptions
td JOIN
casefiletasks cft ON td.tasktypeid=cft.tasktypeid WHERE cft.taskid =
1841 )AS
NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'
I am trying to get the output to look like "Task ID: 1234 - Admin - Investigator : John Doe". However I am having trouble on this part:
CAST((select DISTINCT td.TaskTypeDesc from CaseFileTaskDescriptions td
JOIN CaseFileTasks cft ON td.TaskTypeID=cft.TaskTypeID
where cft.TaskID =1841 )as nvarchar(100))
This seems to work but the problem is I have to hard code the value "1841" to make it work. Is there a way to assign a "taskID" variable with the values being returned from the TaskID select query, or will it not work since I think sql runs everything at once instead of line by line.
EDIT-this is in Microsoft SQL Server Management Studio 2008
You can dynamically reference a column that exists in your FROM set. In this case, it would be any column from casefiletasks or investigators. You would replace 1841 with the table.column reference.
Update
Replacing your static integer with the column reference, your query would look like:
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast((SELECT DISTINCT td.tasktypedesc FROM casefiletaskdescriptions
td JOIN
casefiletasks cft ON td.tasktypeid=cft.tasktypeid WHERE cft.taskid =
cf.taskid )AS
NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'
Would this work as your inner query?
SELECT DISTINCT td.TaskTypeDesc FROM CaseFileTaskDescriptions td
JOIN CaseFileTasks cft ON td.TaskTypeID = cft.TaskTypeID
WHERE cft.TaskID = cf.TaskID
Why not just do another join instead of a subquery?
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast(td.tasktypedesc AS NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
JOIN casefiletaskdescriptions td
ON td.tasktypeid = cf.tasktypeid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'

n to n relationship how to obtain a result in one row

so I have an employee that can work in many companies so I have an n to n relationship, how can I obtain the companies that one employee works in, in just one row with sql?
example
table - employee
Employeeid employeename
1 mike
table company
companyId CompanyName
1 cocacola
2 nokia
3 intel
table employeeCompany
id employeeid companyid
1 1 1
2 1 2
3 1 3
I thought with this but can´t
select Employeeid , companyid
from employeeCompany
where employeeid = 1
group by Employeeid , companyid
Easiest way to do it in Sql Server is by use of FOR XML PATH. The cryptic part .value('text()[1]','nvarchar(max)') handles special xml characters.
select employee.*, companies.*
from Employee
OUTER APPLY
(
select stuff ((SELECT ', ' + Company.CompanyName
FROM EmployeeCompany
INNER JOIN Company
ON EmployeeCompany.CompanyId = Company.CompanyID
WHERE EmployeeCompany.employeeid = Employee.EmployeeID
ORDER BY Company.CompanyName
FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(max)')
, 1, 2, '') Companies
) companies
See demo at Sql Fiddle.
It sounds like you want something that is similar to mySQL's Group_Concat in SQL Server?
If you are looking for a way to do this so that each companyid is in a separate column, then that would only be possible with some difficulty using dynamic SQL. At which time it might be easier to just return this to an application and let it handle what it needs within its own logic?
BTW, the dynamic SQL logic would go something like this in case you were wondering...notice how nasty it is...thus why I would suggest against it.
select #highestCount = max(count(*))
from employeeCompany
group by Employeeid
declare createtemptable varchar(max), #filltableselect varchar(max), #filltablejoin varchar(max)
declare #currentCount int
set #currentCount = 0
set #createtemptable = 'CREATE TABLE #Temp (EmployeeID INT'
set #filltableselect = 'INSERT INTO #Temp SELECT EmployeeCompany0.EmployeeID, EmployeeCompany0.CompanyID'
set #filltablejoin = 'FROM EmployeeCompany AS EmployeeCompany0'
while(#currentCount < #highestCount)
begin
set #createtemptable = #createtemptable + ', CompanyID'
+ CAST(#currentCount AS VARCHAR(2)) + ' INT'
if(#currentCount > 0)
begin
set #filltableselect = #filltableselect + ', EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2)) + '.CompanyId'
set #filltablejoin = #filltablejoin
+ 'LEFT JOIN EmployeeCompany AS EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2))
+ ' ON EmployeeCompany0.EmployeeID = EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2)) + '.EmployeeID'
end
set #currentCount = #currentCount + 1
end
set #createtemptable = #createtemptable + ')'
--This next line can be whatever you need it to be
set #filltablejoin = #filltablejoin + 'WHERE employeeCompany0.EmployeeID = 1'
exec #createtemptable
exec #filltableselect + #filltablejoin