How to optimize the sql query - sql

This query takes dynamic input in the place of cg.ownerid IN (294777,228649 ,188464).when the input increases in the IN condition the query is taking too much time to execute. Please suggest me a way to optimize it.
For example, the below query is taking 4 seconds, if I reduce the list to just IN(188464) its just taking 1 second.
SELECT *
FROM
(SELECT *,
Row_number() OVER(
ORDER BY datecreated DESC) AS rownum
FROM
(SELECT DISTINCT c.itemid,
(CASE WHEN (Isnull(c.password, '') <> '') THEN 1 ELSE 0 END) AS password,
c.title,
c.encoderid,
c.type,
(CASE WHEN c.author = 'education' THEN 'Discovery' ELSE c.type END) AS TYPE,
c.publisher,
c.description,
c.author,
c.duration,
c.copyright,
c.rating,
c.userid,
Stuff(
(SELECT DISTINCT ' ' + NAME AS [text()]
FROM firsttable SUB
LEFT JOIN secondtable AS rgc ON thirdtable = rgc.id
WHERE SUB.itemid = c.itemid
FOR xml path('')), 1, 1, '')AS [Sub_Categories]
FROM fourthtable AS cg
LEFT JOIN item AS c ON c.itemid = cg.itemid
WHERE Isnull(title, '') <> ''
AND c.active = '1'
AND c.systemid = '20'
AND cg.ownerid IN (294777,
228649,
188464)) AS a) AS b
WHERE rownum BETWEEN 1 AND 32
ORDER BY datecreated DESC

As I haven't further information, I just would suggest a first change of your where clause. They should be moved to a subquery as you left join those columns.
SELECT *
FROM(
SELECT *,
Row_number() OVER(
ORDER BY datecreated DESC) AS rownum
FROM
(SELECT DISTINCT c.itemid,
(CASE WHEN (Isnull(c.password, '') <> '') THEN 1 ELSE 0 END) AS password,
c.title,
c.encoderid,
c.type,
(CASE WHEN c.author = 'education' THEN 'Discovery' ELSE c.type END) AS TYPE,
c.publisher,
c.description,
c.author,
c.duration,
c.copyright,
c.rating,
c.userid,
Stuff(
(
SELECT DISTINCT ' ' + NAME AS [text()]
FROM firsttable SUB
LEFT JOIN secondtable AS rgc ON thirdtable = rgc.id
WHERE SUB.itemid = c.itemid
FOR xml path('')
), 1, 1, ''
) AS [Sub_Categories]
FROM (
SELECT cg.itemid
FROM fourthtable as cg
WHERE cg.ownerid IN (294777,228649, 188464)
) AS cg
LEFT JOIN (
SELECT DISTINCT c.itemid, c.type, c.author, c.title, c.encoderid, c.type, c.publisher, c.description, c.author, c.duration, c.copyright, c.rating,c.userid
FROM item as c
WHERE Isnull(c.title, '') <> ''
AND c.active = '1'
AND c.systemid = '20'
) AS c
ON c.itemid = cg.itemid
) AS a
) AS b
WHERE rownum BETWEEN 1 AND 32
ORDER BY datecreated DESC
But not quite sure if everything is connected right away, your missing some aliases which makes it hard for me to get through your query. But I thing you'll get my idea. :-)

With this little information it's impossible to give any specific ideas, but the normal general things apply:
Turn on statistics io and check what's causing most of the logical I/O and try to solve that
Look at the actual plan and check if there's something that doesn't look ok, for example:
Clustered index / table scans (new index could solve this)
Key lookups with a huge amount of rows (adding more columns to index could solve this, either as normal or included fields)
Spools (new index could solve this)
Big difference between estimated and actual number of rows (10x, 100x and so on)
To give any better hints you should really include the actual plan, table / index structure at least on the essential parts and tell what is too much time (seconds, minutes, hours?)

Related

How can i eliminate dups?

select C.Id as candidateId,C.Name, C.Phone, Status.ResultStatusText , Status.TimeStamp, Status.notes ,
(Select count(*) from CandidateCallHistory where CandiateId = candidateId) AS numbCalls,
(SELECT SUBSTRING((SELECT ',' + Name
FROM Jobs
WHERE Id in (select value from fn_Split(c.JobIds,','))
FOR XML PATH('')),2,200000)) AS jobsList
from Candidate2 C
outer APPLY (select top 1 CH.CandiateId, CH.ResultStatusText , CH.TimeStamp , CH.notes
from CandidateCallHistory CH
where CH.CandiateId = C.Id
order by TimeStamp desc) as Status
where Status.ResultStatusText <> 'completed' and Status.ResultStatusText <> 'canceled' and c.isactive = 1
I have multiple records in the CandidateCallHistory table and seems this is causing issue with the outer apply ( i may be wrong) as it should only get the most recent record in the table since it selects top 1.
Try to add distinct in first line after select:
select distinct [...]

How can I optimize the SQL query?

I have a query an SQL query as follows, can anybody suggest any optimization for this; I think most of the effort is being done for the Union operation - is there anything else can be done to get the same result ?
Basically I wanna query first portion of the UNION and if for each record there is no result then the second portion need to be run. Please help.
:
SET dateformat dmy;
WITH incidentcategory
AS (
SELECT 1 ord, i.IncidentId, rl.Description Category FROM incident i
JOIN IncidentLikelihood l ON i.IncidentId = l.IncidentId
JOIN IncidentSeverity s ON i.IncidentId = s.IncidentId
JOIN LikelihoodSeverity ls ON l.LikelihoodId = ls.LikelihoodId AND s.SeverityId = ls.SeverityId
JOIN RiskLevel rl ON ls.RiskLevelId = rl.riskLevelId
UNION
SELECT 2 ord, i.incidentid,
rl.description Category
FROM incident i
JOIN incidentreportlikelihood l
ON i.incidentid = l.incidentid
JOIN incidentreportseverity s
ON i.incidentid = s.incidentid
JOIN likelihoodseverity ls
ON l.likelihoodid = ls.likelihoodid
AND s.severityid = ls.severityid
JOIN risklevel rl
ON ls.risklevelid = rl.risklevelid
) ,
ic AS (
SELECT ROW_NUMBER() OVER (PARTITION BY i.IncidentId ORDER BY (CASE WHEN incidentTime IS NULL THEN GETDATE() ELSE incidentTime END) DESC,ord ASC) rn,
i.incidentid,
dbo.Incidentdescription(i.incidentid, '',
'',
'', '')
IncidentDescription,
dbo.Dateconverttimezonecompanyid(closedtime,
i.companyid)
ClosedTime,
incidenttime,
incidentno,
Isnull(c.category, '')
Category,
opencorrectiveactions,
reportcompleted,
Isnull(classificationcompleted, 0)
ClassificationCompleted,
Cast (( CASE
WHEN closedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
IncidentClosed,
Cast (( CASE
WHEN investigatorfinishedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationFinished,
Cast (( CASE
WHEN investigationcompletetime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationComplete,
Cast (( CASE
WHEN investigatorassignedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigatorAssigned,
Cast (( CASE
WHEN (SELECT Count(*)
FROM incidentinvestigator
WHERE incidentid = i.incidentid
AND personid = 1588
AND tablename = 'AdminLevels') = 0
THEN 0
ELSE 1
END ) AS BIT)
IncidentInvestigator,
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader,
incidentstatus,
incidentstatussearch
FROM incident i
LEFT OUTER JOIN incidentcategory c
ON i.incidentid = c.incidentid
WHERE i.isdeleted = 0
AND i.companyid = 158
AND incidentno <> 0
--AND reportcompleted = 1
--AND investigatorassignedtime IS NOT NULL
--AND investigatorfinishedtime IS NULL
--AND closedtime IS NULL
),
ic2 AS (
SELECT * FROM ic WHERE rn=1
)
SELECT * FROM ic2
--WHERE rownumber >= 0
-- AND rownumber < 0 + 10
--WHERE ic2.incidentid in(53327,53538)
--WHERE ic2.incidentid = 53338
ORDER BY incidentid DESC
Following is the execution plan I got:
https://www.dropbox.com/s/50dcpelr1ag4blp/Execution_Plan.sqlplan?dl=0
There are several issues:
1) use UNION ALL instead of UNION ALL to avoid the additional operation to aggregate the data.
2) try to modify the numerous function calls (e.g. dbo.Incidentdescription() ) to be an in-lie table valued function so you can reference it using CROSS APPLY or OUTER APPLY. Especially, if those functions referencing a table again.
3) move the subqueries from the SELECT part of the query to the FROM part using CROSS APPLY or OUTER APPLY again.
4) after the above is done, check the execution plan again for any missing indexes. Also, run the query with STATISTICS TIME, IO on to verify that the number of times a table
is referenced is correct (sometimes the execution plan put you in the wrong direction, especially if function calls are involved)...
Since the first inner query produces rows with ord=1 and the second produces rows with ord=2, you should use UNION ALL instead of UNION. UNION will filter out equal rows and since you will never get equal rows it is more efficient to use UNION ALL.
Also, rewrite your query to not use the WITH construct. I've had very bad experiences with this. Just use regular derived tables instead. In the case the query is still abnormally slow, try to serialize some derived tables to a temporary table and query the temporary table instead.
Try alternate approach by removing
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader
from the SELECT. Avoid using complex functions/sub-queries in select.

Performance of select over order by case join

I have been wrestling with this for a while, in some cases below sql takes over 30min to execute on a table with 100k rows in current and about 10 is pending. This is a portion of a larger join statement that I have identified as being the culprit. Basically the purpose of the sql is to sort a join of current rows and copies of pending rows so that all pending rows are either at the top or bottom. It's part of a management of change framework. Any ideas how this could be done in a mannaer that performs consistently well? For the record in some cases the same sql runs in under 10sec on tables that have 10M rows and 100s of pending changes. The problem is compounded by the fact that sorting is done on the calculated field. Database is ms sql server 2008 R2.
Update: I'm adding the rest of the joins to show there is semi reason in the madness.
Again the sole purpose of this is to get a combination of current and pending records, to show how a future table will look like after changes has been approved, sorted so the changes are shown either at top or bottom (ASC or DSC on the hasPending), the extra Current2 join is to add some additional identifying data.
Generally it does what its supposed to be doing, fairly decent response times of a few seconds, 10 when reaching around 10M records, however is a few cases everything consistenly slows to a crawl, with responsetimes shooting up to 12-30min.
WITH [ResultPage] AS
SELECT
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN [Current].[ID] IN
(SELECT [CID]
FROM [Pending] AS p
INNER JOIN [Current] ON [Current].[ID] like p.[CID]
WHERE (p.[User] = 'admin'))
THEN 1
ELSE 0
END ASC,
[Current].[ID] ASC) AS [RowID],
[Current].[ID],
CASE WHEN [Current].[ID] IN
(SELECT [CID]
FROM [Pending] AS p
INNER JOIN [Current] ON [Current].[ID] like p.[CID]
WHERE (p.[User] = 'admin'))
THEN 1
ELSE 0
END AS [HasPending]
FROM [Current]
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
SELECT [ResultPage].[RowID], [ResultPage].[HasPending], [Current2].[ID] As [Current2^ID], [Tag].Name],
etc... etc...
FROM [ResultPage]
INNER JOIN [Current] ON ([Current].[ID] = [ResultPage].[ID])
INNER JOIN [Current2] ON ([Current].[T2ID] = [Current2].[ID])
WHERE (([ResultPage].[RowID] BETWEEN -1 AND 50)) ORDER BY [ResultPage].[RowID] ASC
I guess having a double subquery is quite expensive. It might perform better if you determine the [hasPending] in a single subquery and save on some JOIN's.
SELECT
[sub].[ID],
ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
[sub].[hasPending]
FROM
(
SELECT
[Current].[ID],
(CASE WHEN COUNT([pending].[ID]) > 0 THEN 1 ELSE 0 END) AS [hasPending]
FROM [Current]
INNER JOIN [Current2]
ON [Current].[T2ID] = [Current2].[ID]
LEFT JOIN [Pending]
ON [Current].[ID] = [Pending].[ID] AND [Pending].[User] = 'Admin'
GROUP BY [Current].[ID]
) AS [sub]
Edit: Changed COUNT(*) to COUNT([pending].[ID]) in order to determine [hasPending] correctly.
Give this a try, this should speed it up since the ids will be dumped to a table variable and not have to be queried every single loop. This is most likely not the best solution but without further info about what you are trying to do this should at least help.
declare #ids table
(
id int
)
insert into #ids(id)
SELECT [ID] From [Pending]
Inner Join [Current] On [Current].[ID] = [Pending].[ID]
WHERE ([Pending].[User] = 'admin')
SELECT ROW_NUMBER() OVER
(ORDER BY Case When [Current].[ID] In (select id from #ids)
THEN 1 ELSE 0 END ASC, [Current].[ID] ASC) As [RowID],
[Current].[ID],
Case When [Current].[ID] In (select id from #ids)
THEN 1 ELSE 0 END AS [HasPending]
FROM [Current]
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
You could also use this if your ids are unique which I assume they are:
SELECT ROW_NUMBER() OVER
(ORDER BY a.haspending, a.[ID] ASC) As [RowID],
a.id, a.haspending,
from (select [Current].[ID],
Case when a.id is not null THEN 1 ELSE 0 END [HasPending]
FROM [Current]
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
left join (SELECT distinct [ID] From [Pending]
Inner Join [Current] On [Current].[ID] = [Pending].[ID]
WHERE ([Pending].[User] = 'admin')) a on a.id = [Current].[ID]) a
Alright, with the help of Jacco's suggestion and modifying it to give the right results I am after, I was able to get it running, cutting the query down to an astonishing 1sec...
WITH [ResultPage] AS
(SELECT
sub.id as id,
ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
[sub].[hasPending]
FROM
(
SELECT
a.[ID],
(CASE WHEN p.[CID] is not null THEN 1 ELSE 0 END) AS [hasPending]
FROM [Alarm] a
full outer JOIN [Pending] as p
ON a.[ID] like p.[CID]
GROUP BY a.[ID],p.[CID]
) AS [sub]
INNER JOIN [Current2] ON (sub.[T2ID] = [Current2].[ID]))
SELECT [ResultPage].[RowID], [ResultPage].[HasPending], [Current2].[ID] As [Current2^ID],
etc...etc...
FROM [ResultPage]
INNER JOIN [Current] ON ([Current].[ID] = [ResultPage].[ID])
INNER JOIN [Current2] ON ([Current].[T2ID] = [Current2].[ID])
WHERE (([ResultPage].[RowID] BETWEEN -1 AND 50)) ORDER BY [ResultPage].[RowID] ASC

Inner join that ignore singlets

I have to do an self join on a table. I am trying to return a list of several columns to see how many of each type of drug test was performed on same day (MM/DD/YYYY) in which there were at least two tests done and at least one of which resulted in a result code of 'UN'.
I am joining other tables to get the information as below. The problem is I do not quite understand how to exclude someone who has a single result row in which they did have a 'UN' result on a day but did not have any other tests that day.
Query Results (Columns)
County, DrugTestID, ID, Name, CollectionDate, DrugTestType, Results, Count(DrugTestType)
I have several rows for ID 12345 which are correct. But ID 12346 is a single row of which is showing they had a row result of count (1). They had a result of 'UN' on this day but they did not have any other tests that day. I want to exclude this.
I tried the following query
select
c.desc as 'County',
dt.pid as 'PID',
dt.id as 'DrugTestID',
p.id as 'ID',
bio.FullName as 'Participant',
CONVERT(varchar, dt.CollectionDate, 101) as 'CollectionDate',
dtt.desc as 'Drug Test Type',
dt.result as Result,
COUNT(dt.dru_drug_test_type) as 'Count Of Test Type'
from
dbo.Test as dt with (nolock)
join dbo.History as h on dt.pid = h.id
join dbo.Participant as p on h.pid = p.id
join BioData as bio on bio.id = p.id
join County as c with (nolock) on p.CountyCode = c.code
join DrugTestType as dtt with (nolock) on dt.DrugTestType = dtt.code
inner join
(
select distinct
dt2.pid,
CONVERT(varchar, dt2.CollectionDate, 101) as 'CollectionDate'
from
dbo.DrugTest as dt2 with (nolock)
join dbo.History as h2 on dt2.pid = h2.id
join dbo.Participant as p2 on h2.pid = p2.id
where
dt2.result = 'UN'
and dt2.CollectionDate between '11-01-2011' and '10-31-2012'
and p2.DrugCourtType = 'AD'
) as derived
on dt.pid = derived.pid
and convert(varchar, dt.CollectionDate, 101) = convert(varchar, derived.CollectionDate, 101)
group by
c.desc, dt.pid, p.id, dt.id, bio.fullname, dt.CollectionDate, dtt.desc, dt.result
order by
c.desc ASC, Participant ASC, dt.CollectionDate ASC
This is a little complicated because the your query has a separate row for each test. You need to use window/analytic functions to get the information you want. These allow you to do calculate aggregation functions, but to put the values on each line.
The following query starts with your query. It then calculates the number of UN results on each date for each participant and the total number of tests. It applies the appropriate filter to get what you want:
with base as (<your query here>)
select b.*
from (select b.*,
sum(isUN) over (partition by Participant, CollectionDate) as NumUNs,
count(*) over (partition by Partitipant, CollectionDate) as NumTests
from (select b.*,
(case when result = 'UN' then 1 else 0 end) as IsUN
from base
) b
) b
where NumUNs <> 1 or NumTests <> 1
Without the with clause or window functions, you can create a particularly ugly query to do the same thing:
select b.*
from (<your query>) b join
(select Participant, CollectionDate, count(*) as NumTests,
sum(case when result = 'UN' then 1 else 0 end) as NumUNs
from (<your query>) b
group by Participant, CollectionDate
) bsum
on b.Participant = bsum.Participant and
b.CollectionDate = bsum.CollectionDate
where NumUNs <> 1 or NumTests <> 1
If I understand the problem, the basic pattern for this sort of query is simply to include negating or exclusionary conditions in your join. I.E., self-join where columnA matches, but columns B and C do not:
select
[columns]
from
table t1
join table t2 on (
t1.NonPkId = t2.NonPkId
and t1.PkId != t2.PkId
and t1.category != t2.category
)
Put the conditions in the WHERE clause if it benchmarks better:
select
[columns]
from
table t1
join table t2 on (
t1.NonPkId = t2.NonPkId
)
where
t1.PkId != t2.PkId
and t1.category != t2.category
And it's often easiest to start with the self-join, treating it as a "base table" on which to join all related information:
select
[columns]
from
(select
[columns]
from
table t1
join table t2 on (
t1.NonPkId = t2.NonPkId
)
where
t1.PkId != t2.PkId
and t1.category != t2.category
) bt
join [othertable] on (<whatever>)
join [othertable] on (<whatever>)
join [othertable] on (<whatever>)
This can allow you to focus on getting that self-join right, without interference from other tables.

SQL Server - Conditional Join to whatever table is not null

Badly phrased title my apologies.
I am trying to join a table to one of two other tables
MasterTable
SubTable
SubTableArchive
So, MasterTable contains an ID field.
SubTable and SubTableArchive contain a MasterTableId field for the join.
But, data will only ever exist in one of these SubTables. So I just want to join to whichever table has the data in it.
But the only way I know of doing it is by joining to both and using isnull's on all the fields im selecting, and its quickly becoming complicated to read (and write).
Especially because some of the fields are already wrapped in ISNULL's
SELECT M.Id, ISNULL(S.Field1, SA.field1), ISNULL(S.field2, SA.Field2),
SUM(CASE WHEN (ISNULL(S.Finished,SA.Finished)=1 AND ISNULL( ISNULL(S.ItemCode,SA.ItemCode),'')='') THEN 1 WHEN (ISNULL(S.Finished,SA.Finished)=0 AND ISNULL( ISNULL(S.AltItemCode,SA.AltItemCode),'')='') THEN 1 ELSE 0 END) AS SummaryField
FROM MAsterTable M
LEFT OUTER JOIN SubTable S ON S.MasterTableId = M.Id
LEFT OUTER JOIN SubTableArchive SA ON S.MasterTableId = M.Id
GROUP BY M.Id, ISNULL(S.Field1, SA.field1), ISNULL(S.field2, SA.Field2)
So that is working, but its not pretty.
Thats a sample, but the real queries are longer and more convoluted.
I was hoping SQL might have had some sort of conditional joining functionality built in.
Something to do what I am trying to do and leave the query itslef a little friendlier.
Another option is to use a UNION and then use INNER JOINs
SELECT M.x, S.x
FROM MAsterTable M INNER JOIN SubTable S ON S.MasterTableId = M.Id
UNION
SELECT M.x, STA.x
FROM MAsterTable M INNER JOIN SubTableArchive STA ON STA.MasterTableId = M.Id
From a maintenance point of view, if you make the above union a view, you can then apply where filters and sorts to the view, which should simplify matters.
Use sub-select or better WITH statement (code not tested):
WITH SubTable_WithArchive
AS (SELECT Field1, Field2, Finished, ItemCode, AltItemCode, MasterTableID
FROM SubTable
UNION ALL
SELECT Field1, Field2, Finished, ItemCode, AltItemCode, MasterTableID
FROM SubTableArchive
)
SELECT M.Id,
S.Field1,
S.Field2,
SUM(CASE
WHEN s.Finished = 1 AND ISNULL(s.ItemCode, '') == '' THEN 1
WHEN s.Finished = 0 AND ISNULL(s.AltItemCode, '') == '' THEN 1
ELSE 0
END)
AS SummaryField
FROM MasterTable M
LEFT OUTER JOIN SubTable_WithArchive S
ON S.MasterTableId = M.Id
GROUP BY M.Id, S.Field1, s.field2
No, unfortunately, there isn't.
Try this
SELECT M.Id, S.Field1,S.field2,
SUM(CASE WHEN S.Finished=1 AND ISNULL( S.ItemCode,'')='')
THEN 1
WHEN S.Finished=0 AND ISNULL( S.AltItemCode,'')='')
THEN 1 ELSE 0 END) AS SummaryField
FROM MAsterTable M
JOIN (
SELECT id,field1,field2,ItemCode,AltItemCode,finished
FROM subTable
UNION
SELECT id,field1,field2,ItemCode,AltItemCode,finished
FROM subTableArchive
) S ON S.id = M.Id
GROUP BY M.Id, S.Field1,S.field2
Because a ID value from MasterTable will exist in only one table (SubTable or SubTableArchive) you can use this query:
SELECT MasterTableId Id, Field1, Field2,
SUM(CASE
WHEN Finished=1 AND ItemCode IS NULL THEN 1 --OR ISNULL(ItemCode,'') = ''
WHEN Finished=0 AND AltItemCode IS NULL THEN 1 --OR ISNULL(AltItemCode,'') = ''
ELSE 0
END) AS SummaryField
FROM SubTable
GROUP BY 1, 2, 3
UNION ALL
SELECT MasterTableId Id, Field1, Field2,
SUM(CASE
WHEN Finished=1 AND ItemCode IS NULL THEN 1 --OR ISNULL(ItemCode,'') = ''
WHEN Finished=0 AND AltItemCode IS NULL THEN 1 --OR ISNULL(AltItemCode,'') = ''
ELSE 0
END) AS SummaryField
FROM SubTableArchive
GROUP BY 1, 2, 3