Joins - two tables - join

I am new to Databases. I came across a peculiar problem with two tables. Please let me know the solution. Please fnd the scenario below
a ProductCentre table
prdcntrId (primary key), prdcntrname
a ApplicationType table
apptypeid (primary key)
prdcntreid(foreign key to ProductCentre )
apptypname
ProductCentre table || ApplicationType table
||
prdcntrId prdcntrname || apptypeid prdcntreid apptypname
001 Delhi || 11 001 Busines
002 Mumbai || 12 003 Engg
003 Hyd || 13 001 Soft
14 002 Science
The end result should be like this
A productcentre can have any type of applications like Delhi can have many busines, soft applications same with mumbai, hyd
---------------------------------------------------------------------
prdcntrname Busines Engg Soft Science
---------------------------------------------------------------------
Delhi 1 0 1 0
---------------------------------------------------------------------
Mumbai 0 1 0 1
---------------------------------------------------------------------
Hyd 0 1 0 0
---------------------------------------------------------------------
Is this solution possible from these two tables. Please help me in this scenario
Thanks,
KK

You can try using a PIVOT
Something like (Sql Server)
DECLARE #ProductCentre table(
prdcntrId INT,
prdcntrname VARCHAR(50)
)
DECLARE #ApplicationType table(
apptypeid INT,
prdcntreid INT,
apptypname VARCHAR(50)
)
INSERT INTO #ProductCentre SELECT 001,'Delhi'
INSERT INTO #ProductCentre SELECT 002,'Mumbai'
INSERT INTO #ProductCentre SELECT 003,'Hyd'
INSERT INTO #ApplicationType SELECT 11,001,'Busines'
INSERT INTO #ApplicationType SELECT 12,003,'Engg'
INSERT INTO #ApplicationType SELECT 13,001,'Soft'
INSERT INTO #ApplicationType SELECT 14,002,'Science'
SELECT p.*
FROM #ProductCentre p INNER JOIN
#ApplicationType a ON p.prdcntrId = a.prdcntreid
PIVOT
(COUNT(apptypname) FOR apptypname IN ([Busines],
[Engg],
[Soft],
[Science])) p

If the `apptypname' types are fixed then this can work:
select
c.prdcntrname,
Busines = (select count(*)
from ApplicationType at
where at.prdcntreid = c.prdcntreid and apptypname = 'Business'),
Engg = (select count(*)
from ApplicationType at
where at.prdcntreid = c.prdcntreid and apptypname = 'Engg'),
Soft = (select count(*)
from ApplicationType at
where at.prdcntreid = c.prdcntreid and apptypname = 'Soft'),
Science = (select count(*)
from ApplicationType at
where at.prdcntreid = c.prdcntreid and apptypname = 'Science'),
from ProductCentre c
order by c.prdcntrname

Related

What table or view can I get a Work Items Tags in TFS 2017?

I have a recent request to include Work ItemTag information in a daily SSRS report that I generate. I was led to the SQL query below. The problem is that I cannot find a table or a view with the "WorkItemsAre" in the name. So giving that I have the WorkItemSK, System_Id, ProjectSK and CollectionGUID among many other things, how and where can I get the tags querying directly against the TFS database (I know querying against the TFS databases is not recommended but It's in my requirements)?
SELECT DISTINCT WorkItemsAre.ID, WorkItemsAre.Title, tbl_TagDefinition.Name
--,tbl_PropertyValue.ArtifactId, *
FROM tbl_TagDefinition
LEFT JOIN tbl_PropertyDefinition ON tbl_PropertyDefinition.Name =
'Microsoft.TeamFoundation.Tagging.TagDefinition.' + CONVERT(NVARCHAR(400),
tbl_TagDefinition.TagId)
LEFT JOIN tbl_PropertyValue ON tbl_PropertyValue.PropertyId =
tbl_PropertyDefinition.PropertyId
--LEFT JOIN WorkItemLongTexts ON WorkItemLongTexts.ID =
tbl_PropertyValue.ArtifactId
left join WorkItemsAre on WorkItemsAre.ID = tbl_PropertyValue.ArtifactId
WHERE
(
SELECT SUM(CASE WHEN IntValue = 0 THEN 1 ELSE -1 END) NB
FROM tbl_PropertyValue PROP_CNT
WHERE PROP_CNT.PropertyId = tbl_PropertyDefinition.PropertyId
AND WorkItemsAre.ID = PROP_CNT.ArtifactId
) > 0
TFS warehouse does not contain tags. For TFS 2018 (maybe also for tfs 2017) you can find information in table tbl_WorkItemCoreLatest in operational database (in my case: Tfs_DefaultCollection)
SELECT DISTINCT tbl_WorkItemCoreLatest.Id,tbl_TagDefinition.Name
--,tbl_PropertyValue.ArtifactId, *
FROM tbl_TagDefinition
LEFT JOIN tbl_PropertyDefinition ON tbl_PropertyDefinition.Name = 'Microsoft.TeamFoundation.Tagging.TagDefinition.' + CONVERT(NVARCHAR(400), tbl_TagDefinition.TagId)
LEFT JOIN tbl_PropertyValue ON tbl_PropertyValue.PropertyId = tbl_PropertyDefinition.PropertyId
--LEFT JOIN WorkItemLongTexts ON WorkItemLongTexts.ID = tbl_PropertyValue.ArtifactId
left join tbl_WorkItemCoreLatest on tbl_WorkItemCoreLatest.Id = tbl_PropertyValue.ArtifactId
WHERE
(
SELECT SUM(CASE WHEN IntValue = 0 THEN 1 ELSE -1 END) NB
FROM tbl_PropertyValue PROP_CNT
WHERE PROP_CNT.PropertyId = tbl_PropertyDefinition.PropertyId
AND tbl_WorkItemCoreLatest.Id = PROP_CNT.ArtifactId
) > 0

SQLite LEFT JOIN count(*)?

I need to join two tables (well, actually two views) so that for every selected row of the left view, there is a count of rows from the right view. That sounds to me like a LEFT JOIN, but in SQLite (this test database) and a LEFT JOIN query:
SELECT TARGET.session_id session_id, TARGET.labeltype_id labeltype_id, TARGET.label_id label_id, count(SECONDARY.label_id) NOlabels
FROM segment_extended TARGET LEFT JOIN segment_extended SECONDARY
WHERE TARGET.session_id = SECONDARY.session_id AND TARGET.lt_name= "Word" AND SECONDARY.lt_name ="Comments"
AND ((SECONDARY.start <= TARGET.start AND TARGET.END <= SECONDARY.END) OR (TARGET.start <= SECONDARY.start AND SECONDARY.END <= TARGET.END))
AND TARGET.label != '' AND SECONDARY.label != ''
GROUP BY TARGET.session_id,TARGET.labeltype_id, TARGET.label_id;
I get only a small subset of what I would expect:
2 3 3 1
2 3 9 1
A more extended query gives the correct result:
SELECT session_id, labeltype_id, label_id, max(NOlabels) NOlabels
FROM (SELECT TARGET.session_id session_id, TARGET.labeltype_id labeltype_id, TARGET.label_id label_id, count(SECONDARY.label_id) NOlabels
FROM segment_extended TARGET , segment_extended SECONDARY
WHERE TARGET.session_id = SECONDARY.session_id AND TARGET.lt_name= "Word" AND SECONDARY.lt_name ="Comments"
AND ((SECONDARY.start <= TARGET.start AND TARGET.END <= SECONDARY.END) OR (TARGET.start <= SECONDARY.start AND SECONDARY.END <= TARGET.END))
AND TARGET.label != '' AND SECONDARY.label != ''
GROUP BY TARGET.session_id,TARGET.labeltype_id, TARGET.label_id
UNION
SELECT TARGET.session_id session_id, TARGET.labeltype_id labeltype_id, TARGET.label_id label_id, 0 NOlabels
FROM segment_extended TARGET
WHERE TARGET.lt_name= "Word"
AND TARGET.label != ''
GROUP BY TARGET.session_id,TARGET.labeltype_id, TARGET.label_id)
GROUP BY session_id, labeltype_id, label_id
ORDER BY session_id,labeltype_id, label_id
session_id labeltype_id label_id NOlabels
2 3 2 0
2 3 3 1
2 3 4 0
2 3 5 0
2 3 7 0
2 3 8 0
2 3 9 1
2 3 10 0
but it seems unnecessarily complicated. What am I doing wrong with the left join?
When doing a left join you have to count the null values from the left join as 0 records but still include them. You can accomplish this with a CASE construct in the inner query, then using the SUM aggregate function in the outer group-by.
SELECT session_id, labeltype_id, label_id, sum(has_label) NOlabels
FROM (
SELECT TARGET.session_id session_id, TARGET.labeltype_id labeltype_id, TARGET.label_id label_id, CASE WHEN SECONDARY.label_id is NULL then 0 else 1 END has_label
FROM
segment_extended TARGET
LEFT JOIN
segment_extended SECONDARY on
TARGET.session_id = SECONDARY.session_id
AND SECONDARY.lt_name ="Comments"
AND ((
SECONDARY.start <= TARGET.start AND TARGET.END <= SECONDARY.END)
OR (TARGET.start <= SECONDARY.start AND SECONDARY.END <= TARGET.END))
AND SECONDARY.label != ''
WHERE TARGET.lt_name= "Word" AND TARGET.label != '')
GROUP BY session_id, labeltype_id, label_id
Your join is not a left join.
A left join adds NULL values for the right table if there are no rows that match the join condition.
However, you query does not have a join condition, and the WHERE condition is not affect by the LEFT JOIN clause.
Replace WHERE with ON.

Joining two record sets into one result including NULL values

I have sql script like below:
select a.Program,a.COUNTS_OPEN,b.COUNTS_CLOSE
from
(select Program, count(ISNULL(Program,'UNKNOWN')) COUNTS_OPEN
from table_a
WHERE (SUBMITDATE > CONVERT(datetime, '2014-08-31 23:59:59.000') and SUBMITDATE < CONVERT(datetime, '2014-10-01 00:00:00.000') )
group by Program) as a
full JOIN
(
select Program,count(ISNULL(Program,'UNKNOWN')) COUNTS_CLOSE
from table_a
WHERE (STATUS='Closed' and UPDATEDATE > CONVERT(datetime, '2014-08-31 23:59:59.000') and UPDATEDATE < CONVERT(datetime, '2014-10-01 00:00:00.000') )
group by Program) as b
on a.Program= b.Program
and in the result there are two rows of NULL, But I'm expecting for one row NULL as it's grouped by program. here is the result set:
Program COUNTS_OPEN COUNTS_CLOSE
NULL NULL 8
NULL 18 NULL
ProgramA 253 205
ProgramB 2 2
ProgramC 123 109
in stead of two rows NULL, I need one row like:
Program COUNTS_OPEN COUNTS_CLOSE
NULL 18 8
ProgramA 253 205
ProgramB 2 2
ProgramC 123 109
can't figure it out how to how to join correctly.
Without knowing your table structure this is a guess, but I think this query using conditional aggregation should accomplish what you want:
SELECT
Program, -- replace with ISNULL(Program,'UNKNOWN'), if you want UNKNOWN instead of NULL
COUNTS_OPEN = SUM(case when (SUBMITDATE > CONVERT(datetime, '2014-08-31 23:59:59.000') and SUBMITDATE < CONVERT(datetime, '2014-10-01 00:00:00.000') ) then 1 else 0 end),
COUNTS_CLOSED = SUM(case when (STATUS='Closed' and UPDATEDATE > CONVERT(datetime, '2014-08-31 23:59:59.000') and UPDATEDATE < CONVERT(datetime, '2014-10-01 00:00:00.000') ) then 1 else 0 end)
FROM table_a
GROUP BY program

How can I group 5 sub-queries counting total based on the value in one field in child table into one update

I've inherited a solution where a Stored Procedure is triggered as a post process to calculate the total number of each type of communique in the child table and update the Parent table.
The query is not optimal resulting in timeouts if the number of Child rows to the parent are more than 2-3000.
It feels as if this could be solved by grouping each of the communication types in one query instead of 5 different ones.
I'm thinking something like this pseudo code:
UPDATE Parent SET Total = query.Total, email = query.email, letter = query.letter, spoken = query.spoken, written = query.written
JOIN ... as query
WHERE Parent.ParentID = #pid
Is my gut feeling correct or are SQL Server able to optimize this internally?
Adding an index might be an option, but each of the sub queries are as far as I can see hitting one.
The stored procedure looks like this:
CREATE PROCEDURE [dbo].[UpdateParentTotal]
#pid int
AS
UPDATE Parent
-- count Total
set Total = (select count(*) from Child
where Child.ParentID = Parent.ParentID),
-- count Type "email" total
email = (select count(*) from Child
where Child.ParentID = Parent.ParentID and Type = 1),
-- count Type "letter" total
letter = (select count(*) from Child
where Child.ParentID = Parent.ParentID and Type = 2),
-- count Total for Spoken word
spoken = (select count(*) from Child
where Child.ParentID = Parent.ParentID and Type > 99),
-- count all types of written word
written = (select count(*) from Child
where Child.ParentID = Parent.ParentID and ((Type > 1 and Type < 100) or Type is null))
where ParentID = #pid
GO
PS. Naming the question was really hard, since I don't know exactly what kind of solution I need.
You're correct in how you are thinking ... you can put all of these calculations into a single query, then connect to that. See below for an example.
UPDATE Parent
SET
Total = CountTotal,
Email = CountEmail
Letter = CountLetter
Spoken = CountSpoken
Written = CountWritten
FROM
Parent
INNER JOIN
(
SELECT
ParentID,
COUNT(*) CountTotal,
COUNT(CASE WHEN [Type] = 1 THEN 1 END) AS CountEmail,
COUNT(CASE WHEN [Type] = 2 THEN 1 END) AS CountLetter,
COUNT(CASE WHEN [Type] >99 THEN 1 END) AS CountSpoken,
COUNT(CASE WHEN (([Type] > 1 and [Type] < 100) or [Type] is null)) THEN 1 END) AS CountWritten,
FROM Child
GROUP BY ParentID
) Child ON
Parent.ParentID = Child.ParentID
WHERE Parent.ParentID = #pid
You can use a conditional count to summarise your child table by parentID, e.g.
SELECT ParentID,
Email = COUNT(CASE WHEN [Type] = 1 THEN 1 END),
Letter = COUNT(CASE WHEN [Type] = 2 THEN 1 END),
Spoken = COUNT(CASE WHEN [Type] > 99 THEN 1 END),
Written = COUNT(CASE WHEN ([Type] = > 1 AND [Type] < 100) OR [Type] IS NULL THEN 1 END),
Total = COUNT(*)
FROM Child
GROUP BY ParentID
Then it is just a case of incorporating this into your update statement:
WITH ChildSummary AS
( SELECT ParentID,
Email = COUNT(CASE WHEN [Type] = 1 THEN 1 END),
Letter = COUNT(CASE WHEN [Type] = 2 THEN 1 END),
Spoken = COUNT(CASE WHEN [Type] > 99 THEN 1 END),
Written = COUNT(CASE WHEN ([Type] = > 1 AND [Type] < 100) OR [Type] IS NULL THEN 1 END),
Total = COUNT(*)
FROM Child
GROUP BY ParentID
)
UPDATE P
SET Total = ISNULL(cs.Total, 0),
Email = ISNULL(cs.Email, 0),
Letter = ISNULL(cs.Letter, 0),
Spoken = ISNULL(cs.Spoken, 0),
Written = ISNULL(cs.Written, 0)
FROM Parent AS p
LEFT JOIN ChildSummary AS cs
ON cs.ParentID = p.ParentID
WHERE p.ParentID = #Pid;

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery

declare #ProductDetails as table(ProductName nvarchar(200),ProductDescription nvarchar(200),
Brand nvarchar(200),
Categry nvarchar(200),
Grop nvarchar(200),
MRP decimal,SalesRate decimal,CurrentQuantity decimal,AvailableQty decimal)
declare #AvailableQty table(prcode nvarchar(100),Aqty decimal)
declare #CloseStock table(pcode nvarchar(100),
Cqty decimal)
insert into #CloseStock
select PCODE ,
0.0
from producttable
insert into #AvailableQty
select PCODE ,
0.0
from producttable
--Current Qty
--OpenQty
update #CloseStock set Cqty=((OOQTY+QTY+SRRQTY+PYQTY)-(STQTY+PRRQTY))
from
(
select PC.PCODE as PRODUCTCODE,
--Opening
(select case when SUM(PU.Quantity)is null then 0 else SUM(PU.Quantity) end as Q from ProductOpeningYearEnd PU
where PC.PCODE=PU.ProductName) as OOQTY,
--Purchase
(select case when SUM(PU.quantity)is null then 0 else SUM(PU.quantity) end as Q from purchase PU
where PC.PCODE=PU.prdcode ) as QTY,
--Sales
(select case when SUM(ST.QUANTITY)is null then 0 else SUM(ST.QUANTITY)end as Q2 from salestable ST
where PC.PCODE=ST.PRODUCTCODE and ST.status!='cancel' )as STQTY,
--Physical Stock
(select case when SUM(PS.Adjustment)is null then 0 else SUM(PS.Adjustment)end as Q3 from physicalstock PS
where PC.PCODE=PS.PCODE )as PYQTY,
--Sales Return
(select case when SUM(SR.quantity)is null then 0 else SUM(SR.quantity)end as Q3 from salesreturn SR
where PC.PCODE=SR.prdcode )as SRRQTY,
--Purchase Return
(select case when SUM(PR.quantity)is null then 0 else SUM(PR.quantity)end as Q3 from purchasereturn PR
where PC.PCODE=PR.prdcode )as PRRQTY
from producttable PC
group by PC.PCODE
)t
where PCODE=t.PRODUCTCODE
--Available
update #AvailableQty set Aqty=((CCqty-GIQty)+(GOQty))
--((OOQTY+QTY+SRRQTY+PYQTY)-(STQTY+PRRQTY))
from
(
select PC.PCODE as PRODUCTCODE,
--GoodsIn
(select case when SUM(GI.quantity)is null then 0 else SUM(GI.quantity) end as Q from goodsin GI
where PC.PCODE=GI.productcode) as GIQty,
--GoodsOut
(select case when SUM(GUT.quantity)is null then 0 else SUM(GUT.quantity) end as Q from goodsout GUT
where PC.PCODE=GUT.productcode ) as GOQty,
--Current Stock
(select CS.Cqty as Q from #CloseStock CS
where PC.PCODE=CS.pcode ) as CCqty
from producttable PC
group by PC.PCODE
)t
where prcode=t.PRODUCTCODE
insert into #ProductDetails
select PCODE,[DESCRIPTION],BRAND,CATEGORY,DEPARTMENT,MRP,SALERATE,0,0
from producttable
update #ProductDetails set CurrentQuantity=pcqty,AvailableQty=acqty
from
(
select pt.ProductName as pn,cs.Cqty as pcqty,ac.Aqty as acqty from #ProductDetails pt
inner join #CloseStock cs on pt.ProductName=cs.pcode
inner join #AvailableQty ac on pt.ProductName=ac.prcode
)t
where ProductName=t.pn
select * from #ProductDetails
end
This not working when productable in pcode field add ant (-.&) this kind of symbol i want to even allow in pcode field,
please help me how i can allow any symbol in query
(problem with this code)
update #AvailableQty set Aqty=((CCqty-GIQty)+(GOQty))
from
(
select PC.PCODE as PRODUCTCODE,
--GoodsIn
(select case when SUM(GI.quantity)is null then 0 else SUM(GI.quantity) end as Q from goodsin GI
where PC.PCODE=GI.productcode) as GIQty,
--GoodsOut
(select case when SUM(GUT.quantity)is null then 0 else SUM(GUT.quantity) end as Q from goodsout GUT
where PC.PCODE=GUT.productcode ) as GOQty,
--Current Stock
(select CS.Cqty as Q from #CloseStock CS
where PC.PCODE=CS.pcode ) as CCqty
from producttable PC
group by PC.PCODE
)t
where prcode=t.PRODUCTCODE
The problem here isn't with the symbols you're using, it's that you are assigning the value of a subquery to a single column in the result set. For example:
(select case when SUM(PR.quantity)is null then 0 else SUM(PR.quantity)end as Q3 from purchasereturn PR
where PC.PCODE=PR.prdcode )as PRRQTY
Note that this is allowed only if the subquery returns only a single value; otherwise, we don't know which of the values should be assigned to the column.
If you expect your subqueries to return multiple values and you just want an arbitrary one, use TOP 1 in the subquery to only return 1 value. Otherwise, you'll have to debug each subquery to figure out which returns multiple results and is causing the issue.

Resources