Selecting Distinct Fields From Joined Rows - sql

I have a table ANIMAL and another table CALF_PARENT
Design of ANIMAL table is:
ID PK IDENTITY(1,1),
TagNo varchar(30)
and other columns...
Design of CALF_PARENT is:
ID PK IDENTITY(1,1),
Parent int (FK from Animal),
IsMother varchar(1)
I am writing following query to join two tables:
SELECT a.[TagNo]
,a.ID
,a2.TagNo
,isnull(cp.Parent,0)
,a3.TagNo
,isnull(cp.Parent,0)
FROM [dbo].[ANIMAL] a
LEFT JOIN [CALF_PARENT] cp
ON a.ID = cp.Calf
LEFT JOIN ANIMAL a2
ON a2.ID = cp.Parent AND cp.IsMother = 'Y' AND a2.ID IS NOT NULL
LEFT JOIN ANIMAL a3
ON a3.ID = cp.Parent AND cp.IsMother = 'N' AND a3.ID IS NOT NULL
Its returning me record like this:
Tag, CalfID, FatherTagNo, FatherID, MotherTagNo, MotherID
FA-56 21 AB-670 3
FA-56 21 CW-59 7
I want it to return me single row like this:
Tag, CalfID, FatherTagNo, FatherID, MotherTagNo, MotherID
FA-56 21 AB-670 3 CW-59 7
What would be the simplest way to implement it.

SELECT DISTINCT a.[TagNo] As Tag
,a.ID As CalfID
,MAX(a2.TagNo) As FatherTagNo
,MAX(isnull(cp.Parent,0)) As FatherID
,MAX(a3.TagNo) As MotherTagNo
,MAX(isnull(cp.Parent,0))As MotherID
FROM [dbo].[ANIMAL] a
LEFT JOIN [CALF_PARENT] cp
ON a.ID = cp.Calf
LEFT JOIN ANIMAL a2
ON a2.ID = cp.Parent AND cp.IsMother = 'Y' AND a2.ID IS NOT NULL
LEFT JOIN ANIMAL a3
ON a3.ID = cp.Parent AND cp.IsMother = 'N' AND a3.ID IS NOT NULL
GROUP BY a.[TagNo] ,a.ID
and with example
declare #t table (id varchar(10),cal int,father varchar(10),fatherid int,mother varchar(20),motherid int)
insert into #t(id,cal,father,fatherid,mother,motherid) values ('FA-56',21,'AB-670',3,NULL,NULL)
insert into #t(id,cal ,father,fatherid,mother,motherid) values ('FA-56',21,null,null, 'CW-59',21)
select distinct id As i,cal,MAX(father),MAX(fatherid),MAX(mother),MAX(motherid) from #t
group by id,cal

try this:
SELECT a.*, cpmd.*, cpfd.*
FROM dbo.ANIMAL a
LEFT JOIN CALF_PARENT cpm ON a.ID = cpm.Calf AND cpm.IsMother = 'Y'
LEFT JOIN ANIMAL cpmd ON cpmd.ID = cpm.Parent
LEFT JOIN CALF_PARENT cpf ON a.ID = cpf.Calf AND cpf.IsMother = 'N'
LEFT JOIN ANIMAL cpfd ON cpfd.ID = cpf.Parent
and your life would be easier if your calf_parent table would consist of 3 columns:
Animal_ID (PK), Father_ID, Mother_ID

Related

Query to get all siblings

I have table like that:
ID NAME SURNAME MotherID FatherID
0 JJ smi NULL NULL
1 ja rly NULL NUL
2 ak smi 0 1
3 ol smi 0 1
4 oa woo 2 3
5 oe boo 2 3
etc.
I need query that with specific parameter as NAME and surname will return me all siblings of a person.
Expected output
NAME SURNAME FATHERNAME FATHERSURNAME MOTHERNAME MOTHERSURNAME
AK SMI JA RLY JJ SMI
OL SMI JA RLY JJ SMI
I tried
SELECT
a.name,
a.surname
FROM PEOPLE a, PEOPLE b
WHERE (b.name = 'ak' AND b.surname ='smi' AND
(b.motherID = a.ID OR b.fatherid = ID))
You can use a SUB QUERY to achieve this.
Table Creation:
DECLARE #T TABLE(
ID INT,
NAME VARCHAR(MAX),
SURNAME VARCHAR(MAX),
MOTHERID INT,
FATHERID INT)
Table Insertion:
Insert into #t Values(0,'JJ','smi',NULL,NULL)
Insert into #t Values(1,'ja','rly',NULL,NULl)
Insert into #t Values(2,'ak','smi',0,1)
Insert into #t Values(3,'ol','smi',0,1)
Insert into #t Values(4,'oa','woo',2,3)
Insert into #t Values(5,'oe','boo',2,3)
Query:
SELECT S.NAME AS NAME,S.SURNAME AS SURNAME,S.FATHER_NAME ,S.FATHER_SURNAME,M.NAME AS
MOTHER_NAME,M.SURNAME AS MOTHER_SURNAME
FROM #T M INNER JOIN(
SELECT T2.NAME AS NAME,T2.SURNAME AS SURNAME,T1.NAME AS FATHER_NAME,T1.SURNAME AS
FATHER_SURNAME,T2.MOTHERID
FROM #T T1
INNER JOIN #T T2 ON T1.ID=T2.FATHERID
WHERE T2.NAME IN ('AK','OL'))S ON M.ID=S.MOTHERID
Output:
Also ,add the WHERE clause based on your parameter requirement.
Here is one way you can get it. From here you can explore a few other options!
CREATE PROC GetSiblings
(
#GivenName AS VARCHAR(100),
#SurName AS VARCHAR(100)
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
A.GivenName,
A.SurName,
F.GivenName AS FatherGivenName,
F.SurName AS FatherSurName,
M.GivenName AS MotherGivenName,
M.SurName AS MotherSurName,
FROM PEOPLE AS P INNER JOIN PEOPLE AS F ON P.FatherID = F.ID
INNER JOIN PEOPLE AS M ON P.MotherID = M.ID
WHERE P.GivenName = #GivenName AND P.SurName = #SurName
UNION --By father
SELECT
A.GivenName,
A.SurName,
F.GivenName AS FatherGivenName,
F.SurName AS FatherSurName,
M.GivenName AS MotherGivenName,
M.SurName AS MotherSurName,
FROM PEOPLE AS P INNER JOIN PEOPLE AS F ON P.FatherID = F.ID
INNER JOIN PEOPLE AS M ON P.MotherID = M.ID
WHERE P.FatherID IN (SELECT DISTINCT FatherID FROM PEOPLE WHERE GivenName = #GivenName AND SurName = #SurName)
UNION --By mother
SELECT
A.GivenName,
A.SurName,
F.GivenName AS FatherGivenName,
F.SurName AS FatherSurName,
M.GivenName AS MotherGivenName,
M.SurName AS MotherSurName,
FROM PEOPLE AS P INNER JOIN PEOPLE AS F ON P.FatherID = F.ID
INNER JOIN PEOPLE AS M ON P.MotherID = M.ID
WHERE P.MotherID IN (SELECT DISTINCT MotherID FROM PEOPLE WHERE GivenName = #GivenName AND SurName = #SurName);
END;

Return two relationship in one resultset

Below are the oversimplified inspired from my production schema.
Thus, I want to return all these information in one result set.
My desired result set
I have tried this query but it return wrong result.
SELECT u.*
,f.*
,uv.*
,v.*
FROM User u
LEFT JOIN UserFarm uf ON uf.UserID = u.ID
LEFT JOIN Farm f ON f.ID = uf.FarmID
LEFT JOIN FarmVehicle fv ON f.ID = fv.FarmID
LEFT JOIN UserVehicle uv ON u.ID = uv.UserID
LEFT JOIN Vehicle v ON fv.VehicleID = v.ID
WHERE u.ID = 1
Edit: This is the result from above query.
Could anyone advise me on this, I really need to return in the desired result.
You could build a query to return the data you want in the first row, and null in the columns you don't want for that row. Then create another query for the second row and use union all to combine the data together:
declare #UserVehicle table (UserID int, VehicleID int, IsService bit)
declare #User table (ID int, Name varchar(10))
declare #UserFarm table (UserID int, FarmID int)
declare #Farm table (ID int, Name varchar(10))
declare #FarmVehicle table (FarmID int, VehicleID int)
declare #Vehicle table (ID int, [Type] varchar(10), Name varchar(10))
insert into #UserVehicle values (1, 2, 1)
insert into #User values (1, 'Sam')
insert into #UserFarm values (1, 1)
insert into #Farm values (1, 'Flora')
insert into #FarmVehicle values (1, 1)
insert into #Vehicle values (1, 'Larry', 'Scania'), (2, 'Unknown', 'Civic')
select [User.ID] = u.ID
,[User.Name] = u.Name
,[Farm.ID] = f.ID
,[Farm.Name] = f.Name
,[UserVehicle.UserID] = null
,[UserVehicle.VehicleID] = null
,[UserVehicle.IsService] = null
,[Vehicle.ID] = v.ID
,[Vehicle.Name] = v.Name
from #User u
left join #UserFarm uf on u.ID = uf.UserID
left join #Farm f on uf.FarmID = f.ID
left join #FarmVehicle fv on f.ID = fv.VehicleID
left join #Vehicle v on fv.VehicleID = v.ID
union all
select [User.ID] = u.ID
,[User.Name] = u.Name
,[Farm.ID] = null
,[Farm.Name] = null
,[UserVehicle.UserID] = uv.UserID
,[UserVehicle.VehicleID] = uv.VehicleID
,[UserVehicle.IsService] = case when uv.IsService = 0 then 'No' else 'Yes' end
,[Vehicle.ID] = v.ID
,[Vehicle.Name] = v.Name
from #User u
left join #UserFarm uf on u.ID = uf.UserID
left join #UserVehicle uv on u.ID = uv.UserID
left join #Vehicle v on uv.VehicleID = v.ID
This query returns the following dataset:
User.ID User.Name Farm.ID Farm.Name UserVehicle.UserID UserVehicle.VehicleID UserVehicle.IsService Vehicle.ID Vehicle.Name
----------- ---------- ----------- ---------- ------------------ --------------------- --------------------- ----------- ------------
1 Sam 1 Flora NULL NULL NULL 1 Scania
1 Sam NULL NULL 1 2 Yes 2 Civic
If you do not want to see users who are not assigned to vehicles or farms, then change all left join to inner join.
Try with following query
SELECT U.*,T.* FROM (
SELECT F.FARMID,F.NAME AS NAM
,UV.*
,V.*
FROM VEHICLE V
LEFT JOIN FARMVEHICLE FV ON FV.VEHICLEID = V.ID
LEFT JOIN USERVEHICLE UV ON UV.VEHICLEID = V.ID
LEFT JOIN FARM F ON F.FARMID = FV.FARMID
LEFT JOIN USERFARM UF ON UF.FARMID = F.FARMID)T, USER U
Let me know if any issue in query.
You want to show a user's farms and vehicles. However farms and vehicles can be related, and in that case you want to show them together in a row rather than in separated rows.
Example: User1 is related to Farm1, Farm2, and Farm3 and to Vehicle1, Vehicle2, and Vehicle3. Moreover, Farm1 is related to Vehicle1 and Vehicle2 and Farm2 is also related to Vehicle1.
Then you want:
user | farm | vehicle
------+-------+---------
User1 | Farm1 | Vehicle1
User1 | Farm1 | Vehicle2
User1 | Farm2 | Vehicle1
User1 | Farm3 | -
User1 | - | Vehicle3
So the second and third columns show the relations of farms with vehicles. You get these with a full outer join. The join's ON clause is a bit tricky. You want the userid to match and the combination of farmid and vehicleid to be found in the bridge table farmvehicle. Here is one way to do this:
with rel as
(
select coalesce(uf.userid, uv.userid) as userid, uf.farmid, uv.vehicleid
from userfarm uf
full outer join uservehicle uv
on uf.userid = uv.userid
and exists (select * from farmvehicle fv where fv.farmid = uf.farmid
and fv.vehicleid = uv.vehicleid)
)
select u.name as user_name, f.name as farm_name, v.name as vehicle_name
from usr u
left join rel on u.id = rel.userid
left join farm f on f.id = rel.farmid
left join vehicle v on v.id = rel.vehicleid
order by user_name, farm_name, vehicle_name;
Rextester demo: http://rextester.com/DNKSU25931

SQL Filtering rows with no duplicate value

Hi so I'm new to SQL and I'm trying to find a way in which I can obtain only the rows that have values that are not duplicate to each other in a specific column of table.
For example the Table below is called T1 and contains:
ID|Branch ID
1 444
2 333
3 444
4 111
5 555
6 333
The result I want will be
ID|Branch ID
4 111
5 555
So only showing non duplicate rows
Edit: I want to apply this to a large relational code. Here is a snippet of where I want it to be added
FROM dbo.LogicalLine
INNER JOIN dbo.Page ON dbo.LogicalLine.page_id = dbo.Page.id
INNER JOIN dbo.Branch ON dbo.LogicalLine.branch_id = dbo.Branch.id
The table LogicalLine will have a column called branch_id containing duplicate id values. I wish to filter those out showing only the non-duplicate branch_id like above example then INNER JOIN the Branch table into the LogicalLine which I have done.
Added -Full Code here:
SELECT
(SELECT name
FROM ParentDevice
WHERE (Dev1.type NOT LIKE '%cable%') AND (id = Dev1.parent_device_id))T1_DeviceID,
(SELECT name
FROM Symbol
WHERE (id = CP1.symbol_id) AND (type NOT LIKE '%cable%'))T1_DeviceName,
(SELECT name
FROM Location
WHERE (id = Page.location_id))T1_Location,
(SELECT name
FROM Installation
WHERE (id = Page.installation_id))T1_Installation,
(SELECT name
FROM ParentDevice
WHERE (Dev2.type NOT LIKE '%cable%') AND (id = Dev2.parent_device_id))T2_DeviceID,
(SELECT name
FROM Symbol
WHERE ( id = CP2.symbol_id) AND (type NOT LIKE '%cable%'))T2_DeviceName,
(SELECT name
FROM Location
WHERE (id = PD2.location_id))T2_Location,
(SELECT name
FROM Installation
WHERE (id = Page.installation_id))T2_Installation,
(SELECT devicefamily
FROM Device
WHERE (type LIKE '%cable%') AND (id = SymCable.device_id))CablePartNumber,
(SELECT name
FROM ParentDevice
WHERE (id = DevCable.parent_device_id) AND (DevCable.type LIKE '%cable%'))CableTag
FROM dbo.LogicalLine
INNER JOIN dbo.Page ON dbo.LogicalLine.page_id = dbo.Page.id
INNER JOIN dbo.Branch ON dbo.LogicalLine.branch_id = dbo.Branch.id
LEFT OUTER JOIN dbo.Symbol AS SymCable ON dbo.LogicalLine.cable_id = SymCable.id
LEFT OUTER JOIN dbo.Device AS DevCable ON SymCable.device_id = DevCable.id
LEFT OUTER JOIN dbo.ParentDevice AS ParentCable ON DevCable.parent_device_id = ParentCable.id
INNER JOIN dbo.SymbolCP AS CP1 ON dbo.Branch.cp1_id = CP1.id
INNER JOIN dbo.SymbolCP AS CP2 ON dbo.Branch.cp2_id = CP2.id
INNER JOIN dbo.Symbol AS S1 ON CP1.symbol_id = S1.id
INNER JOIN dbo.Symbol AS S2 ON CP2.symbol_id = S2.id
INNER JOIN dbo.Device AS Dev1 ON S1.device_id = Dev1.id
INNER JOIN dbo.Device AS Dev2 ON S2.device_id = Dev2.id
INNER JOIN dbo.ParentDevice AS PD1 ON Dev1.parent_device_id = PD1.id
INNER JOIN dbo.ParentDevice AS PD2 ON Dev2.parent_device_id = PD2.id
INNER JOIN dbo.Location AS L1 ON PD1.location_id = L1.id
INNER JOIN dbo.Location AS L2 ON PD2.location_id = L2.id
INNER JOIN dbo.Installation AS I1 ON L1.installation_id = I1.id
INNER JOIN dbo.Installation AS I2 ON L2.installation_id = I2.id
WHERE
(PD1.project_id = #Projectid) AND (dbo.LogicalLine.drawingmode LIKE '%Single Line%');
Select Id, BranchId from table t
Where not exists
(Select * from table
where id != t.Id
and BranchId = t.BranchId)
or
Select Id, BranchId
From table
Group By BranchId
Having count(*) == 1
EDIT: to modify as requested, simply add to your complete SQL query a Where clause:
Select l.Id BranchId, [plus whatever else you have in your select clause]
FROM LogicalLine l
join Page p ON p.id = l.page_Id
join Branch b ON b.Id = l.branch_id
Group By l.branch_id, [Plus whatever else you have in Select clause]
Having count(*) == 1
or
Select l.Id BranchId, [plus whatever else you have in your select clause]
FROM LogicalLine l
join Page p on p.id = l.page_Id
join Branch b on b.Id = l.branch_id
Where not exists
(Select * from LogicalLine
where id != l.Id
and branch_id = l.branch_id)

Joining Two Temp Tables

I would like to join two temp tables into one big temp table. I want all of the records from my first temp table and want the records from my second temp table ONLY if the ProductID doesn't exist in my first temp table.
First temp table:
--define temporary table
declare #tmp table (
ManagerID int null,
ManagerName varchar(250),
ProductID int null,
ProductName varchar(250),
RFIFixedIncomeAttributionID int null,
Value decimal(8,4) null,
Name varchar(250),
Sector varchar(250)
)
--populate temp table
insert into #tmp
select
m.ManagerID, m.ManagerName, p.ID as 'ProductID', p.ProductName, sa.RFIFixedIncomeAttributionID, sa.Value, sc.Name,
case when gm.GeographicMandateID = 2 and s1.SubType1ID = 10 and s2.SubType2ID = 39 then 'Core'
when gm.GeographicMandateID = 2 and s1.SubType1ID = 10 and s2.SubType2ID = 38 then 'Intermediate'
end as 'Sector'
from Products p
join Managers m on m.ManagerID = p.ManagerID
left join RFIFixedIncomeAttribution fia on fia.ParentID = p.ID and fia.ParentTypeID = 26
left join RFIFixedIncomeSectorAllocation sa on sa.RFIFixedIncomeAttributionID = fia.ID
and sa.RFIFixedIncomeDataTypeID = 1
join RFIFixedIncomeSectorCategories sc on sc.ID = sa.RFIFixedIncomeSectorCategoryID
join SubType1 s1 on s1.SubType1ID = p.SubType1ID
join SubType2 s2 on s2.SubType2ID = p.SubType2ID
join GeographicMandates gm on gm.GeographicMandateID = p.GeographicMandateID
where p.prodclasscategoryid = 4
and fia.year = 2014
and fia.quarter = 6/3
and p.Rank = 1
order by m.ManagerName, p.ProductName
--get filtered dataset
select * from #tmp
where
Sector in ('Core')
Second temp table:
--define temporary table
declare #tmp2 table (
ManagerID int null,
ManagerName varchar(250),
ProductID int null,
ProductName varchar(250),
RFIFixedIncomeAttributionID int null,
Value decimal(8,4) null,
Name varchar(250),
Sector varchar(250)
)
--populate temp table
insert into #tmp2
select
m.ManagerID, m.ManagerName, p.ID as 'ProductID', p.ProductName, sa.RFIFixedIncomeAttributionID, sa.Value, sc.Name,
case when gm.GeographicMandateID = 2 and s1.SubType1ID = 10 and s2.SubType2ID = 39 then 'Core'
when gm.GeographicMandateID = 2 and s1.SubType1ID = 10 and s2.SubType2ID = 38 then 'Intermediate'
end as 'Sector'
from Products p
join Managers m on m.ManagerID = p.ManagerID
join Vehicles v on v.ProductID = p.ID
join ManagerAccounts ma on ma.VehicleID = v.ID
join Accounts a on a.MgrAccountID = ma.MgrAccountID
left join RFIFixedIncomeAttribution fia on fia.ParentID = a.AccountID and fia.ParentTypeID = 6
left join RFIFixedIncomeSectorAllocation sa on sa.RFIFixedIncomeAttributionID = fia.ID
and sa.RFIFixedIncomeDataTypeID = 1
join RFIFixedIncomeSectorCategories sc on sc.ID = sa.RFIFixedIncomeSectorCategoryID
join SubType1 s1 on s1.SubType1ID = p.SubType1ID
join SubType2 s2 on s2.SubType2ID = p.SubType2ID
join GeographicMandates gm on gm.GeographicMandateID = p.GeographicMandateID
where p.prodclasscategoryid = 4
and fia.year = 2014
and fia.quarter = 6/3
and p.Rank = 1
order by m.ManagerName, p.ProductName
--get filtered dataset
select * from #tmp2
where
Sector in ('Core')
Few points that have already brought up
Union is the term you want, join is something quite different.
You are not working with temp tables, you are working with table variables. Not quite the same thing
mysql and mssql are not the same thing, tag your questions as one or the other, not both.
select * from #tmp
union all
select * from #tmp2 where productID not in (select productID from #tmp)
Not sure if I'd rely on this query in MySQL as it'll struggle with the not in clause...you can use the join syntax in Jasmine's answer for the second half of the union clause.
This is a case of "find all rows with NO MATCH in the other table" and we have a pattern for that. First, swap your tables - the table where you expect to be missing rows will be the second or RIGHT table, the other is the LEFT table.
select <columns>
from table1
LEFT OUTER JOIN table1.ID = table2.ID
where table2.ID IS NULL
OR... don't swap the tables and use RIGHT OUTER JOIN - but that's non-standard.
In your code, there's a problem...
and fia.quarter = 6/3
is equivalent to:
and fia.quarter = 2
I think you need some quotation marks there.

two left outer join not working Oracle sql

There are four table in the query
Table a contains a_id , a_name
Table a_tl contains a_tl_id , a_id , language_id , a_disp_name
Table b contains b_id , a_id , b_name
Table b_tl contains b_tl_id , b_id , language_id , b_disp_name
I want to do a left outer join on a and a_tl , a leftouter join on b and b_tl
and a inner join on the resultant tables .I wrote the following query
SELECT case a.a_disp_name
WHEN null THEN a.a_name
else a.a_disp_name
end AS a_name ,
case b.b_disp_name
WHEN null THEN b.b_name
else b.b_disp_name
end AS b_name ,
a_id ,
b_id
FROM a ,
a_tl ,
b ,
b_tl
WHERE a.a_id = a_tl.a_id (+)
AND b.b_id = b_tl.b_id (+)
AND a_tl.language_id = 2
AND b_tl.language_id = 2
AND a.a_id= b.b_id
This query is working of the language_id is present in the database if for a particular value it is not present it will not work i.e. left outer join is not working
Looks like the problem is, that you are not using (+) for your language_id checks.
Your table is outer-joined, so language_id is NULL when no record is found, but then you check for language_id = 2, but ? language_id is NULL.
I also don't see where you use results from a_tl or b_tl, guess that's just a problem of your post, not your original query?
However, please use explicit joins instead of the old syntax. Once you are used to it, it is a lot easier to read and understand.
Your query could also benefit from using COALESCE (or NVL if you like):
SELECT COALESCE( a_tl.a_disp_name, a.a_name ) AS a_name,
COALESCE( b_tl.b_disp_name, b.b_name ) AS b_name,
a.a_id,
b.b_id
FROM a
JOIN b ON ( b.b_id = a.a_id )
LEFT JOIN a_tl ON ( a_tl.a_id = a.a_id AND a_tl.language_id = 2 )
LEFT JOIN b_tl ON ( b_tl.b_id = b.b_id AND b_tl.language_id = 2 )
Hope I got your question right, please ask if it does not work.
If you want a_tl.language_id = 2 you force an inner join(a_tl.language_id would never be null).
If you want to left join only with rows from a_tl with a_tl.language_id = 2, then write like this:
FROM a
join b on (a.a_id= b.b_id)
left join a_tl on ( a.a_id = a_tl.a_id and a_tl.language_id = 2)
left join b_tl on ( b.b_id = b_tl.b_id and b_tl.language_id = 2 )