I need to update a field with concatenated results from a T-SQL query that uses an INNER JOIN and a LEFT JOIN. I was able to do this with the STUFF and FOR XML PATH functions with a simpler query, but my efforts at doing the same process with a more elaborate query have not been successful.
Here is the query that gives me the results I need with the ID field going to end up as the grouping and the Step field will be the one where the concatenated values need to be in the one field per one ID.
SELECT sc.ID, sc.STEP
FROM Table1 As sc
INNER JOIN Table2 As f
ON sc.STEP = f.Step AND sc.STEP_TYPE = f.StepType AND
sc.OldStep = f.OldStep
LEFT JOIN Table3 As l
ON sc.ID = l.ID
WHERE f.Group = l.Group AND sc.CompDate IS NULL
That will give me my results broken down into multiple fields per ID
•ID-----STEP
01 - 101
01 - 102
01 - 103
02 - 107
02 - 113
And what I need is:
•ID-----STEP
01 - 101, 102, 103
02 - 107, 113
Here is what i've tried so far:
;With OA As
( SELECT s.ID, STUFF((
SELECT ', ' + sc.STEP
FROM Table1 As sc
WHERE sc.ID = s.ID
ORDER BY sc.ID
FOR XML PATH('')),1,1,'') As Steps
FROM Table1 As s
INNER JOIN Table2 As f
ON s.STEP = f.Step AND s.STEP_TYPE = f.StepType
AND s.OldStep = f.OldStep
LEFT JOIN Table3 As l
ON s.ID = l.ID
WHERE f.Group = l.Group AND s.CompDate IS NULL
GROUP BY s.ID
)
SELECT * FROM OpenAuditSteps
The problem here is that I am getting a concatenation of all the reocrds, not just the ones grouped on the individual ID's. I've tried various ways of arranging the joins, but nothing has worked so far.
You are very nearly there: You already have your first query working. Assuming the results of that go into #Table1 then
SELECT Distinct
sc1.ID,
STUFF (( Select ',' + sc2.STEP
FROM #Table1 AS SC2
WHERE sc2.ID = sc1.ID
FOR XML PATH('')),1,1,'') AS STEPS
FROM #Table1 AS SC1
ORDER BY sc1.ID
So to combine it into one single query using WITH try this:
;WITH IDSteps AS (
SELECT sc.ID, sc.STEP
FROM Table1 As sc
INNER JOIN Table2 As f
ON sc.STEP = f.Step AND sc.STEP_TYPE = f.StepType AND
sc.OldStep = f.OldStep
LEFT JOIN Table3 As l
ON sc.ID = l.ID
WHERE f.Group = l.Group AND sc.CompDate IS NULL
)
SELECT Distinct
sc1.ID,
STUFF (( Select ',' + sc2.STEP
FROM IDSteps AS SC2
WHERE sc2.ID = sc1.ID
FOR XML PATH('')),1,1,'') AS STEPS
FROM IDSteps AS SC1
ORDER BY sc1.ID;
Related
Tried to join three tables: car, car_and_engine, and engine. The second table, car_and_engine, connects the cars and their engines. A car type has up to three possible engine types. The query is significantly slower than expected (based on experience with similar operations in other languages). Is there anything terribly inefficient about this code?
select engine_type, AVG(horsepower) into #horsepower_by_engine_type
from TRANSPORT.dbo.engine
group by engine_type
go
with temp as(select * from TRANSPORT.dbo.car left join TRANSPORT.dbo.car_and_engine on TRANSPORT.dbo.car_and_engine.car_type_y = TRANSPORT.dbo.car.car_type_x)
select * from temp left join #horsepower_by_engine_type as e1 on temp.engine_type_1 = e1.engine_type
left join #horsepower_by_engine_type as e2 on temp.engine_type_2 = e2.engine_type
left join #horsepower_by_engine_type as e3 on temp.engine_type_3 = e3.engine_type
You don't really need a temp table (except when you are doing some diagnostics). You could replace your temp table syntax with an inline-view.
with temp as(select * from TRANSPORT.dbo.car left join TRANSPORT.dbo.car_and_engine on TRANSPORT.dbo.car_and_engine.car_type = TRANSPORT.dbo.car.car_type)
select * from temp left join
(select engine_type, AVG(horsepower)
from TRANSPORT.dbo.engine
group by engine_type) as e1 on temp.engine_type_1 = e1.engine_type
left join
(select engine_type, AVG(horsepower)
from TRANSPORT.dbo.engine
group by engine_type) as e2 on temp.engine_type_2 = e2.engine_type
left join
(select engine_type, AVG(horsepower)
from TRANSPORT.dbo.engine
group by engine_type) as e3 on temp.engine_type_3 = e3.engine_type
Better still, you could put your summary into your CTE
with temp as (select * from TRANSPORT.dbo.car left join TRANSPORT.dbo.car_and_engine on TRANSPORT.dbo.car_and_engine.car_type = TRANSPORT.dbo.car.car_type),
avgHP as (select engine_type, AVG(horsepower) from TRANSPORT.dbo.engine group by engine_type)
select * from temp left join avgHP as e1 on temp.engine_type_1 = e1.engine_type
left join avgHP as e2 on temp.engine_type_2 = e2.engine_type
left join avgHP as e3 on temp.engine_type_3 = e3.engine_type
Below sample query is a part of my main query. I found SORT operator in below query is consuming 30% of the cost.
To avoid SORT, there is need of creation of Indexes. Is there any other way to optimize this code.
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA
WHERE ID = r.ID
AND Status = 3
AND TableA_ID >ISNULL((
SELECT TOP 1 TableA_ID
FROM TableA
WHERE ID = r.ID
AND Status <> 3
ORDER BY T_Date DESC
), 0)
ORDER BY T_Date ASC
Looks like you can use not exists rather than the sorts. I think you'll probably get a better performance boost by use a CTE or derived table instead of the a scalar subquery.
select *
from r ... left outer join
(
select ID, min(t_date) as min_date from TableA t1
where status = 3 and not exists (
select 1 from TableA t2
where t2.ID = t1.ID
and t2.status <> 3 and t2.t_date > t1.t_date
)
group by ID
) as md on md.ID = r.ID ...
or
select *
from r ... left outer join
(
select t1.ID, min(t1.t_date) as min_date
from TableA t1 left outer join TableA t2
on t2.ID = t1.ID and t2.status <> 3
where t1.status = 3 and t1.t_date < t2.t_date
group by t1.ID
having count(t2.ID) = 0
) as md on md.ID = r.ID ...
It also appears that you're relying on an identity column but it's not clear what those values mean. I'm basically ignoring it and using the date column instead.
Try this:
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA a1
LEFT JOIN (
SELECT ID, MAX(TableA_ID) AS MaxAID
FROM TableA
WHERE Status <> 3
GROUP BY ID
) a2 ON a2.ID = a1.ID AND a1.TableA_ID > coalesce(a2.MAXAID,0)
WHERE a1.ID = r.ID AND a1.Status = 3
ORDER BY T_Date ASC
The use of TOP 1 in combination with the unexplained r alias concern me. There's almost certainly a MUCH better way to get this data into your results that doesn't involve doing this in a sub query (unless this is for an APPLY operation).
I need to group the query below by dda.LA and need to display all the columns listed in the select but almost none of them are aggregated. i don't know what the syntax to get around this is and i can not find a post that shows this syntax (most examples only have one table, two at tops).
Select dda.a,
dda.b,
dda.c,
dda.d,
dda.e,
dda.f,
dda.g,
dda.h,
dda.i,
dda.j,
dda.k,
dda.l,
dda.m,
dda.n,
dda.o,
dda.p,
dda.r,
dda.u,
dda.LA,
dd.aa,
coalesce(apn.apn,Pt.z) as abc,
coalesce(apn.v,Pt.y) as def,
'RFN' RowFocusIndicator ,
'SRI' SelectRowIndicator ,
'Y' Expanded ,
Convert(Int, Null) SortColumn
From dda (NoLock)
Inner Join dd (NoLock) On dda.d = dd.q and dda.e = dd.e
Left Outer Join apn (nolock) on dda.r = apn.r
Left Outer Join Pt (nolock) on dda.s = Pt.t
Where 1 = 1
And dda.u = (Select Min(c.w)
From c (NoLock)
Where c.x = dda.s)
Thanks!
Just add this to any column that you want to aggregate by:
AggregatedColumnName = Aggregation(fieldToAggregate) Over (Partition By dda.LA)
ex.
aCount = Count(dda.a) Over (Partition By dda.LA)
Suppose I've a table like this:
NAME REF1 REF2 DRCT
A (null) Ra D1
A Rb (null) D1
A (null) Rc D2
B Rd (null) D3
B (null) Re D3
I want aggregate this table in something like:
NAME REF1 REF2 DRCT
A Rb Ra D1
A (null) Rc D2
B Rd Re D3
As you can see, i want aggregate each row with same name. I've search through COALESCE and various aggregate functions but I haven't found what i was looking for. Any idea?
Assuming that what I ask in my previous comment is true, (only null or a given value for REF1 and REF2 for each NAME, DRCT pair), this seems to work:
select NAME, M_REF1, M_REF2, DRCT
from (
select A.NAME, coalesce(A.REF1, B.REF1) m_REF1,
coalesce(A.REF2, B.REF2) m_REF2, A.REF1 A_REF1, B.REF1 B_REF1,
A.REF2 A_REF2, B.REF2 B_REF2, A.DRCT
from Table1 A JOIN Table1 B on A.NAME = B.NAME AND A.DRCT = B.DRCT)
WHERE A_REF1 = m_REF1 AND B_REF2 = m_REF2
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;
The union is used because the rows with only one record are not included in the first SELECT.
But this is somewhat simpler, and works too:
select A.NAME, coalesce(A.REF1, B.REF1) M_REF1, coalesce(A.REF2,B.REF2) M_REF2,A.DRCT
from Table1 A LEFT OUTER JOIN Table1 B ON A.DRCT = B.DRCT AND A.NAME = B.NAME
WHERE NVL2(A.REF1,0,1) = 1 AND NVL2(B.REF1,0,1) =0
AND NVL2(A.REF2,0,1) = 0 AND NVL2(B.REF2,0,1) = 1
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;
I'm stuck with a SQL query. I'm making a subquery in the select clause and db2 prompts a -119 error telling:
"An expression starting with "FACILITY_ID" specified in a SELECT clause, HAVING clause, or ORDER BY clause is not specified in the GROUP BY clause or it is in a SELECT clause, HAVING clause, or ORDER BY clause with a column function and no GROUP BY clause is specified. SQL Code: -119, SQL State: 42803"
I don't know how to include NUMTAGS in the GROUP BY. I tried including the BC.ITEM in the GROUP BY clause with no result. I don't know how exactly to look for this in the web, and the forums I looked at were no useful.
If someone could explain me how to mend this or paste a link where I could look for a solution, I would be grateful.
The SQL query is with DB2 and it's down here:
SELECT SS.NAME, B.DESTINATION_ID, P.DESCRIPTION, B.LAST_READ_DATE, B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.FACILITY_ID = B.FACILITY_ID
AND BC.BOX_ID = B.BOX_ID
GROUP BY BC.ITEM) AS NUMTAGS,
B.BOX_ID
FROM PROJECT_DB.BOX B
INNER JOIN MAINDB.DESTINATION P ON B.DESTINATION_ID = P.DESTINATION_ID
INNER JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON B.DESTINATION_ID = WH.DESTINATION_ID
AND B.WAREHOUSE_ID = WH.WAREHOUSE_ID
INNER JOIN MAINDB.SECTION S ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
INNER JOIN MAINDB.DESTINATION_SET SS
ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
GROUP BY B.BOX_ID, B.FACILITY_ID, B.DESTINATION_ID, B.LAST_READ_DATE, B.LABEL, P.DESCRIPTION, SS.NAME
You can correct the statement by: v including the columns in the GROUP
BY clause that are in the SELECT clause, or v removing the columns
from the SELECT clause.
From: DB2 documentation.
You need to put ALL selected columns in your GROUP BY...
Since you're using a scalar sub-select, I don't think you need a GROUP BY clause on either of your statements. Try this:
SELECT
SS.NAME,
B.DESTINATION_ID,
P.DESCRIPTION,
B.LAST_READ_DATE,
B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.FACILITY_ID = B.FACILITY_ID
AND BC.BOX_ID = B.BOX_ID
) AS NUMTAGS,
B.BOX_ID
FROM PROJECT_DB.BOX B
JOIN MAINDB.DESTINATION P
ON B.DESTINATION_ID = P.DESTINATION_ID
JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON B.DESTINATION_ID = WH.DESTINATION_ID
AND B.WAREHOUSE_ID = WH.WAREHOUSE_ID
JOIN MAINDB.SECTION S
ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
JOIN MAINDB.DESTINATION_SET SS
ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
My final working query is this down here. I think I had the wrong tables referenced at the "group by" or something similar:
SELECT SS.NAME, P.DESTINATION_ID, P.DESCRIPTION, B.LAST_READ_DATE, B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.ID_FACILITY = B.ID_FACILITY
AND BC.ID_BOX = B.ID_BOX
GROUP BY BC.ITEM) AS NUMTAGS,
B.BOX_ID, B.FACILITY_ID
FROM PROJECT_DB.BOX B
INNER JOIN MAINDB.DESTINATION P ON B.DESTINATION_ID = P.DESTINATION_ID
INNER JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON WH.WAREHOUSE_ID = B.WAREHOUSE_ID
AND WH.ID_DESTINATION = B.ID_DESTINATION
INNER JOIN MAINDB.SECTION S ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
INNER JOIN MAINDB.DESTINATION_SET SS ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
GROUP BY B.BOX_ID, B.FACILITY_ID, P.DESTINATION_ID, B.LAST_READ_DATE, B.LABEL, P.DESCRIPTION, SS.NAME
WITH UR