Find all lines where a value exists in one line - sql-server

Here is my query
select order_no, pkg_no, zone_no
from T_DETAIL_ITEM a
where order_no = 495
order by order_no, pkg_no
For a given package I have zone number = 0
What I need to do is return all the lines with the pkg_no = 1597. Because one where exists with a zero zone.
I tried a few different 'where exists' lines and it isn't working.

Try to self join.
This way you can put your requirement in the second table "instance" but retrieve everything from that table matches based on another common field.
select distinct a.order_no, a.pkg_no, a.zone_no
from T_DETAIL_ITEM a
join T_DETAIL_ITEM b on b.pkg_no = a.pkg_no
where b.zone_no = 0
order by a.order_no, a.pkg_no

The accepted answer is good, but I had saw that you noted you tried EXISTS, so I wrote this example up using that method.
SELECT *
FROM T_Detail_Item d
WHERE exists (SELECT * FROM T_Detail_Item dx WHERE dx.pkg_no = d.pkg_no AND dx.zone_no = 0)

One way is to self reference the table in a left join and only include those with a zone_no=0, within the join clause. The filter out non-matching records by excluding records that do not match from the left join, T2.pkg_no = NULL.
SELECT
T1.pkg_no, T1.zone_no
FROM
T_DETAIL_ITEM T1
LEFT OUTER JOIN T_DETAIL_ITEM T2 ON T2.pkg_no = T1.pkg_no AND T2.zone_no = 0
WHERE
NOT T2.pkg_no IS NULL

If I correctly understood the question, you need something like this
BEGIN
declare #str varchar(max);
set #str='';
SELECT #str=#str+ [YOURCOLUMB]
FROM [YOURTABLE]
SELECT #str
END

Related

Duplicate and incorrect output sql query

I need to select grade_name from tblgrade, subject_name from tblsubject, count (subscribe_id) from tblsubcription, count (sub_status) from tblsubcription where sub_status=1 and count (sub_status) from tblsubcription where sub_status is null.
This is what i have tried:
SELECT t2.grade_name,
t.subject_name,
(SELECT COUNT(*)
FROM tblsubcription
WHERE sub_status IS NULL
AND teacher_id = 2) AS pending,
(SELECT COUNT(*)
FROM tblsubcription
WHERE sub_status = '1'
AND teacher_id = 2) AS appoved,
COUNT(t1.subscribe_id) AS totalsub
FROM tblsubject t
INNER JOIN tblsubject_grade tg ON (t.subject_id = tg.subject_id)
INNER JOIN tblsubcription t1 ON (tg.subject_garde_id = t1.subject_garde_id)
INNER JOIN tblgrade t2 ON (tg.grade_id = t2.grade_id)
AND tg.grade_id = t2.grade_id
AND tg.subject_id = t.subject_id
AND t2.admin_id = t.admin_id
WHERE t1.teacher_id = 2
GROUP BY t.subject_name,
t2.grade_name;
See result obtained when the above query is executed and the expected result i need is in red
Looking at this subquery:
(SELECT COUNT(*)
FROM tblsubcription
WHERE sub_status IS NULL
AND teacher_id = 2) AS pending,
There is nothing here to relate (correlate) it to the specific row. You need an additional condition in the WHERE clause that tells you which Grade/Subject pair to look at. The other (approved) subquery is the same way.
Alternatively, you may be able to solve this with another join to tblsubscription and conditional aggregation.
I'd post code to fix this, but I find the images too blurry to read well, so I can't easily infer which fields to use. Next time post formatted text, and you'll get a better answer in less time.

Selecting other columns if one column is Null

If B.[Name] has value it well select the the following
Select
B.[Name],
A.[Address],
A.TIN,
A.AuthorizedRep1Name,
A.AuthorizedRep1Email,
A.AuthorizedRep1Contact,
A.AuthorizedRep2Name,
A.AuthorizedRep2Email,
A.AuthorizedRep2Contact,
A.RefundOfSecDep,
A.PayeeAddress,
A.PayeeTIN
From MembersTbl A
join UserTbl B
on A.UserID = B.ID
And if the B.[Name] is Null It will Select the following
Select
A.[Address],
A.TIN,
A.AuthorizedRep1Name,
A.AuthorizedRep1Email,
A.AuthorizedRep1Contact,
A.RefundOfSecDep,
A.PayeeAddress,
A.PayeeTIN
From MembersTbl A
What will I do?
You can check with creating a variable and assigning their values as shown below.
declare #name varchar(20)
set #name = (select name from YourTable b where ...)
Now to check
if(#name is not null)
begin
----Your first query.
end
else
begin
----Your second query
end
You don't need to do extra effort just add left join in your second query as both query return same data except extra columns.
You can use result according to you requirement based on your condition like B.Name is null or not.
Example :
Select
B.[Name],
A.[Address],
A.TIN,
A.AuthorizedRep1Name,
A.AuthorizedRep1Email,
A.AuthorizedRep1Contact,
A.AuthorizedRep2Name,
A.AuthorizedRep2Email,
A.AuthorizedRep2Contact,
A.RefundOfSecDep,
A.PayeeAddress,
A.PayeeTIN
From MembersTbl A
left join UserTbl B
on A.UserID = B.ID
I hope it will help you :)

TSQL Select Statement using Case or Join

I am a little stuck on a situation that I have been trying to fight through. I have a page that allows a user to select all the filter options they want to search by and then it runs the query on that data.
Every field requires something to be picked but on a new field I am introducing, it's going to be optional.
It allows you to provide a list of supervisors and it will then provide all records where the agents supervisor is in the list provided; pretty straight forward. However, I am trying to make this optional as I don't want to always search by users. If I don't provide a name in the UI to pass to the stored procedure, then I want to ignore this part of the statement and get me everything regardless of the manager.
Here is the query I am working with:
SELECT a.[escID],
a.[escReasonID],
b.[ArchibusLocationName],
c.[ArchibusLocationName],
b.[DepartmentDesc],
c.[DepartmentDesc],
a.[escCreatedBy],
a.[escWorkedBy],
a.[escNotes],
a.[preventable],
a.[escalationCreated],
a.[escalationTracked],
a.[feedbackID],
typ.[EscalationType],
typ.[EscalationTypeText] AS escalationType,
d.reasonText AS reasonText
FROM [red].[dbo].[TFS_Escalations] AS a
LEFT OUTER JOIN
red.dbo.EmployeeTable AS b
ON a.escCreatedBy = b.QID
LEFT OUTER JOIN
red.dbo.EmployeeTable AS c
ON a.escWorkedBy = c.QID
LEFT OUTER JOIN
red.dbo.TFS_Escalation_Reasons AS d
ON a.escReasonID = d.ReasonID
INNER JOIN
dbo.TFS_EscalationTypes AS typ
ON d.escType = typ.EscalationType
WHERE B.[ArchibusLocationName] IN (SELECT location
FROM #tmLocations)
AND C.[ArchibusLocationName] IN (SELECT location
FROM #subLocations)
AND B.[DepartmentDesc] IN (SELECT department
FROM #tmDepartments)
AND C.[DepartmentDesc] IN (SELECT department
FROM #subDepartments)
AND DATEDIFF(second, '19700101', CAST (CONVERT (DATETIME, A.[escalationCreated], 121) AS INT)) >= #startDate
AND DATEDIFF(second, '19700101', CAST (CONVERT (DATETIME, A.[escalationCreated], 121) AS INT)) <= #endDate
AND a.[PREVENTABLE] IN (SELECT PREVENTABLE FROM #preventable)
AND b.MgrQID IN (SELECT leaderQID FROM #sourceLeaders)
The part that I am trying to make option is the very last line of the query:
AND b.MgrQID IN (SELECT leaderQID FROM #sourceLeaders)
Essentially, if there is no data in the temp table #sourceLeaders then it should ignore that piece of the query.
In all of the other instances of the WHERE clause, something is always required for those fields which is why that all works fine. I just cant figure out the best way to make this piece optional depending on if the temp table has data in it (the temp table is populated by the names entered in the UI that a user COULD search by).
So this line should be TRUE if something matches data in the table variable OR there is nothing in the table variable
AND
(
b.MgrQID IN (SELECT leaderQID FROM #sourceLeaders)
OR
NOT EXISTS (SELECT 1 FROM #sourceLeaders)
)
Similar to Nick.McDermaid's, but uses a case statement instead :
AND
(
1 = CASE WHEN NOT EXISTS(SELECT 1 FROM #sourceLeaders) THEN 1
WHEN b.MgrQID IN (SELECT leaderQID FROM #sourceLeaders) THEN 1
ELSE 0
END
)
Maybe at the top so you have a single check
DECLARE #EmptySourceLeaders CHAR(1)
IF EXISTS (SELECT 1 FROM #sourceLeaders)
SET #EmptySourceLeaders = 'N'
ELSE
SET #EmptySourceLeaders = 'Y'
Then in the joins
LEFT OUTER JOIN #SourceLeaders SL
ON b.MgrQID = SL.leaderQID
Then in the WHERE
AND (#EmptySourceLeaders = 'Y' OR SL.leaderQID IS NOT NULL)
lots of ways to do it.

Conditional JOIN Statement SQL Server

Is it possible to do the following:
IF [a] = 1234 THEN JOIN ON TableA
ELSE JOIN ON TableB
If so, what is the correct syntax?
I think what you are asking for will work by joining the Initial table to both Option_A and Option_B using LEFT JOIN, which will produce something like this:
Initial LEFT JOIN Option_A LEFT JOIN NULL
OR
Initial LEFT JOIN NULL LEFT JOIN Option_B
Example code:
SELECT i.*, COALESCE(a.id, b.id) as Option_Id, COALESCE(a.name, b.name) as Option_Name
FROM Initial_Table i
LEFT JOIN Option_A_Table a ON a.initial_id = i.id AND i.special_value = 1234
LEFT JOIN Option_B_Table b ON b.initial_id = i.id AND i.special_value <> 1234
Once you have done this, you 'ignore' the set of NULLS. The additional trick here is in the SELECT line, where you need to decide what to do with the NULL fields. If the Option_A and Option_B tables are similar, then you can use the COALESCE function to return the first NON NULL value (as per the example).
The other option is that you will simply have to list the Option_A fields and the Option_B fields, and let whatever is using the ResultSet to handle determining which fields to use.
This is just to add the point that query can be constructed dynamically based on conditions.
An example is given below.
DECLARE #a INT = 1235
DECLARE #sql VARCHAR(MAX) = 'SELECT * FROM [sourceTable] S JOIN ' + IIF(#a = 1234,'[TableA] A ON A.col = S.col','[TableB] B ON B.col = S.col')
EXEC(#sql)
--Query will be
/*
SELECT * FROM [sourceTable] S JOIN [TableB] B ON B.col = S.col
*/
You can solve this with union
select a, b
from tablea
join tableb on tablea.a = tableb.a
where b = 1234
union
select a, b
from tablea
join tablec on tablec.a = tableb.a
where b <> 1234
I disagree with the solution suggesting 2 left joins. I think a table-valued function is more appropriate so you don't have all the coalescing and additional joins for each condition you would have.
CREATE FUNCTION f_GetData (
#Logic VARCHAR(50)
) RETURNS #Results TABLE (
Content VARCHAR(100)
) AS
BEGIN
IF #Logic = '1234'
INSERT #Results
SELECT Content
FROM Table_1
ELSE
INSERT #Results
SELECT Content
FROM Table_2
RETURN
END
GO
SELECT *
FROM InputTable
CROSS APPLY f_GetData(InputTable.Logic) T
I think it will be better to think about your query in a different way and treat them more like sets.
I do believe if you make two separate queries then join them using UNION, It will be much better in performance and more readable.

Join subquery with min

I'm pulling my hair out over a subquery that I'm using to avoid about 100 duplicates (out of about 40k records). The records that are duplicated are showing up because they have 2 dates in h2.datecreated for a valid reason, so I can't just scrub the data.
I'm trying to get only the earliest date to return. The first subquery (that starts with "select distinct address_id", with the MIN) works fine on it's own...no duplicates are returned. So it would seem that the left join (or just plain join...I've tried that too) couldn't possibly see the second h2.datecreated, since it doesn't even show up in the subquery. But when I run the whole query, it's returning 2 values for some ipc.mfgid's, one with the h2.datecreated that I want, and the other one that I don't want.
I know it's got to be something really simple, or something that just isn't possible. It really seems like it should work! This is MSSQL. Thanks!
select distinct ipc.mfgid as IPC, h2.datecreated,
case when ad.Address is null
then ad.buildingname end as Address, cast(trace.name as varchar)
+ '-' + cast(trace.Number as varchar) as ONT,
c.ACCOUNT_Id,
case when h.datecreated is not null then h.datecreated
else h2.datecreated end as Install
from equipmentjoin as ipc
left join historyjoin as h on ipc.id = h.EQUIPMENT_Id
and h.type like 'add'
left join circuitjoin as c on ipc.ADDRESS_Id = c.ADDRESS_Id
and c.GRADE_Code like '%hpna%'
join (select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment)
as h2 on c.address_id = h2.address_id
left join (select car.id, infport.name, carport.number, car.PCIRCUITGROUP_Id
from circuit as car (NOLOCK)
join port as carport (NOLOCK) on car.id = carport.CIRCUIT_Id
and carport.name like 'lead%'
and car.GRADE_Id = 29
join circuit as inf (NOLOCK) on car.CCIRCUITGROUP_Id = inf.PCIRCUITGROUP_Id
join port as infport (NOLOCK) on inf.id = infport.CIRCUIT_Id
and infport.name like '%olt%' )
as trace on c.ccircuitgroup_id = trace.pcircuitgroup_id
join addressjoin as ad (NOLOCK) on ipc.address_id = ad.id
The typical approach to only getting the lowest row is one of the following. You didn't bother to specify what version of SQL Server you're using, what you want to do with ties, and I have little interest to try to work this into your complex query, so I'll show you an abstract simplification for different versions.
SQL Server 2000
SELECT x.grouping_column, x.min_column, x.other_columns ...
FROM dbo.foo AS x
INNER JOIN
(
SELECT grouping_column, min_column = MIN(min_column)
FROM dbo.foo GROUP BY grouping_column
) AS y
ON x.grouping_column = y.grouping_column
AND x.min_column = y.min_column;
SQL Server 2005+
;WITH x AS
(
SELECT grouping_column, min_column, other_columns,
rn = ROW_NUMBER() OVER (ORDER BY min_column)
FROM dbo.foo
)
SELECT grouping_column, min_column, other_columns
FROM x
WHERE rn = 1;
This subqery:
select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment
Probably will return multiple rows because the comment is not guaranteed to be the same.
Try this instead:
CROSS APPLY (
SELECT TOP 1 H2.DateCreated, H2.Comment -- H2.Equipment_id wasn't used
FROM History H2
WHERE
H2.Comment LIKE 'MAC: 5%'
AND C.Address_ID = H2.Address_ID
ORDER BY DateCreated
) H2
Switch that to OUTER APPLY in case you want rows that don't have a matching desired history entry.

Resources