SQL Join with 2 conditions same column but different data names - sql-server

I need to join 2 tables using 2 columns as identifiers,
Reference and UAP
TABLE 1
Reference
UAP
Week 1
Week 2
Table 2
Reference
UAP
Stock
Here is the problem with data on both tables in UAP column
Table 1 Table 2
UAP1 M1
UAP2 M2
UAP3 M3
UAP4 M4
UAP5 M5
UAP6 M6
UAPP PROTOS
EXT EXTR
the UAPS are the same but name is just different
I have no control over the data i'm getting, it's a IBM DB2 remote server
I tried a local table to join but i want to avoid that 'cause of the performance impact (30+ seconds)
So far my query is this
SELECT
*
FROM OPENQUERY(MACPAC,
'SELECT
P.Referencia,
P.UAP,
P.W01,
P.W02,
S.Stock
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON S.Reference = S.Reference
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference')
well of course the ideal would be
SELECT
*
FROM OPENQUERY(MACPAC,
'SELECT
P.Referencia,
P.UAP,
P.W01,
P.W02,
S.Stock
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND P.UAP = S.UAP
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference')
but it does not work cause different names... Is there a way to make this happen without a local join table that will slow my query by several seconds?
Here is the output of these queries individually
This is the production table
This is the stock table
the output should show me the Stock on the production table by Reference and UAP
EDIT
Sorry for confusion the remote server is IBM DB2. This was an error of my coworker that said it was coming from oracle--
Cheers for correct answer from #Sergey Menshov.
SELECT
Reference,
UAP,
W01,
W02
FROM OPENQUERY(MACPAC,
'SELECT
P.Reference,
P.UAP,
P.W01,
P.W02
FROM AUTO.D805DATPOR.Production AS P
LEFT JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND
S.UAP =
CASE P.UAP
WHEN ''UAP1'' THEN ''M1''
WHEN ''UAP2'' THEN ''M2''
WHEN ''UAP3'' THEN ''M3''
WHEN ''UAP4'' THEN ''M4''
WHEN ''UAP5'' THEN ''M5''
WHEN ''UAP6'' THEN ''M6''
WHEN ''UAPP'' THEN ''PROTOS''
WHEN ''EXT'' THEN ''EXTR''
END
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference DESC')
another method which gives error in UAP1 not a column in table L that might work using dual table for DB2
SELECT
Reference,
UAP,
W01,
W02
FROM OPENQUERY(MACPAC,
'SELECT
P.Reference,
P.UAP,
P.W01,
P.W02
FROM AUTO.D805DATPOR.Production AS P
JOIN
(
SELECT ''UAP1'' AS UAP1, ''M1'' AS UAP2 FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP2'',''M2'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP3'',''M3'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP4'',''M4'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP5'',''M5'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAP6'',''M6'' FROM sysibm.sysdummy1
UNION ALL SELECT ''UAPP'',''PROTOS'' FROM sysibm.sysdummy1
UNION ALL SELECT ''EXT'',''EXTR'' FROM sysibm.sysdummy1
) L
ON P.UAP = L.UAP1
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND S.UAP = L.UAP2
WHERE (P.Reference Not Like ''FS%'')
ORDER BY Reference DESC')

Try to use a link-subquery:
FROM AUTO.D805DATPOR.Production AS P
JOIN
(
SELECT ''UAP1'' AS UAP1,''M1'' AS UAP2 FROM DUAL
UNION ALL SELECT ''UAP2'',''M2'' FROM DUAL
UNION ALL SELECT ''UAP3'',''M3'' FROM DUAL
UNION ALL SELECT ''UAP4'',''M4'' FROM DUAL
UNION ALL SELECT ''UAP5'',''M5'' FROM DUAL
UNION ALL SELECT ''UAP6'',''M6'' FROM DUAL
UNION ALL SELECT ''UAPP'',''PROTOS'' FROM DUAL
UNION ALL SELECT ''EXT'',''EXTR'' FROM DUAL
) L
ON P.UAP=L.UAP1 -- !!!
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference AND S.UAP=L.UAP2 -- !!!
Or you can create a link-table in the Oracle and then use it in your query.
I think it'll be better because you can use it in other queries and insert there a new combinations.
Pseudo code:
CREATE TABLE UAP_LINK(
UAP1 VARCHAR2(20) NOT NULL,
UAP2 VARCHAR2(20) NOT NULL,
PRIMARY KEY(UAP1),
UNIQUE(UAP2)
)
INSERT UAP_LINK VALUES
UAP1, M1
UAP2, M2
UAP3, M3
UAP4, M4
UAP5, M5
UAP6, M6
UAPP, PROTOS
EXT , EXTR
One more variant with CASE:
FROM AUTO.D805DATPOR.Production AS P
INNER JOIN AUTO.D805DATPOR.Stock S
ON P.Reference = S.Reference
AND S.UAP=
CASE P.UAP
WHEN ''UAP1'' THEN ''M1''
WHEN ''UAP2'' THEN ''M2''
WHEN ''UAP3'' THEN ''M3''
WHEN ''UAP4'' THEN ''M4''
WHEN ''UAP5'' THEN ''M5''
WHEN ''UAP6'' THEN ''M6''
WHEN ''UAPP'' THEN ''PROTOS''
WHEN ''EXT'' THEN ''EXTR''
END

Related

Create and execute stored procedure in SQL Server

I have four tables:
dbo.Projects (id, ProjectName, Areas, PaymentSystem, Districts.id, purpose.id, types.id, etc)
dbo.Districts(id, DistrictsName)
dbo.Purpose (id, PurposeName) - has residential & commercial
dbo.Types (id, typName)
I want to select DistrictsName where PurposeName = 'residential'
I tried this procedure :
CREATE PROCEDURE [dbo].[SearchResidentialProjects]
AS
SELECT
dbo.Projects.ID,
dbo.Districts.DistrictName,
dbo.Purpose.PurposeName
FROM
dbo.Projects
INNER JOIN
dbo.Purpose ON dbo.Projects.PurposeID = dbo.Purpose.ID
INNER JOIN
dbo.Districts ON dbo.Projects.DistrictID = dbo.Districts.ID
WHERE
dbo.Purpose.PurposeName = N'Residential'
this is the result from this procedure:
ID DistrictsName PurposeName
1 District1 residential
2 District1 residential
3 District2 residential
4 District2 residential
i want display the DistrictsName without duplicate or with different values , i a have also one more project per district in projects records . this what i want to display :
ID DistrictsName PurposeName
1 District1 residential
2 District2 residential
how i get this result ,
any help is appreciated.
Why do people use stored procedures when views are much more appropriate? I have never understood this. It seems peculiar to SQL Server users.
In any case, you can do what you want with aggregation:
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as id,
d.DistrictName, p.PurposeName
FROM dbo.Projects pr INNER JOIN
dbo.Purpose pu
ON pr.PurposeID = pu.ID INNER JOIN
dbo.Districts d
ON pr.DistrictID = d.ID
WHERE pu.PurposeName = N'Residential'
GROUP BY d.DistrictName, p.PurposeName;
The use of table aliases makes the query much easier to write and to read.
In addition, I don't understand the id column being output. Why would you want to construct a new id? In any case, that is what your data suggests.
Use DISTINCT statement for removing the duplicates:
CREATE PROCEDURE [dbo].[SearchResidentialProjects]
AS
SELECT DISTINCT
dbo.Projects.ID,
dbo.Districts.DistrictName,
dbo.Purpose.PurposeName
FROM
dbo.Projects
INNER JOIN
dbo.Purpose ON dbo.Projects.PurposeID = dbo.Purpose.ID
INNER JOIN
dbo.Districts ON dbo.Projects.DistrictID = dbo.Districts.ID
WHERE
dbo.Purpose.PurposeName = N'Residential'

Recursive query SQL Server not working as expected

thanks in advance for you help. I'm still quite new to MS SQL db but I was wondering why my recursive query for MSSQL below does not return the value i'm expecting. I've done my research and at the bottom is the code I came up with. Lets say I have the following table...
CategoryID ParentID SomeName
1 0 hmm
2 0 err
3 0 woo
4 3 ppp
5 4 ttt
I'm expecting the query below to return 3 4 5. I basically wanted to get the list of category id's heirarchy below it self inclusive based on the category id I pass in the recursive query. Thanks for you assistance.
GO
WITH RecursiveQuery (CategoryID)
AS
(
-- Anchor member definition
SELECT a.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS a
WHERE a.ParentID = CategoryID
UNION ALL
-- Recursive member definition
SELECT b.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS b
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = b.ParentID
)
-- Statement that executes the CTE
SELECT o.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS o
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = 3
GO
If you want tree from specific root:
DECLARE #rootCatID int = 3
;WITH LessonsTree (CatID)
AS
(
SELECT a.CategoryID
FROM [EducationDatabase].[dbo].[LessonCategory] AS a
WHERE a.CategoryID = #rootCatID ---<<<
UNION ALL
SELECT b.CategoryID
FROM LessonsTree as t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS b
ON b.ParentID = t.CatID
)
SELECT o.*
FROM LessonsTree t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS o
ON o.CategoryID = t.CatID
As stated in the comments, the anchor isn't restricted. Easiest solution is to add the criterium in the anchor
with RecursiveQuery (theID)
AS
(
SELECT a.ParentID --root id=parentid to include it and to prevent an extra trip to LessonCategory afterwards
FROM [LessonCategory] AS a
WHERE a.ParentID = 3 --restriction here
UNION ALL
SELECT b.CategoryID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT* from RecursiveQuery
Another option is to have the recursive query be general (no restricted anchor) and have it keep the rootid as well. Then the query on the cte can restrict on the rootid (the first option is probably better, this second one is mainly suitable if you are created some sort of root-view)
with RecursiveQuery
AS
(
SELECT a.ParentID theID, a.ParentID RootID
FROM [LessonCategory] AS a
UNION ALL
SELECT b.CategoryID, d.RootID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT theID from RecursiveQuery where RootID = 3

Excluding certain results of the query SQL Server

I have 3 tables: CLIENT, FEATURE, CLIENT_FEATURE
Table CLIENT: id_client, name, surname, address
Table FEATURE: id_feature, feature_txt
Table FEATURE_CLIENT: id_fc, fc_id_client, fc_id_feature
One client can have multiple features.
If I want to see clients with desired 1 feature:
SELECT
[id_client], [name], [surname], [address], [id_feature],
[feature_txt], [id_fc], [fc_id_client], [fc_id_feature]
FROM
[client]
LEFT JOIN
[feature] ON fc_id_client = id_client
WHERE
fc_id_feature = 1
It is ok, but If the client has the feature 1 and 20 and I want to search for clients without feature 20
I tested:
SELECT
[id_client], [name], [surname], [address],[id_feature],
[feature_txt], [id_fc], [fc_id_client], [fc_id_feature]
FROM
[client]
LEFT JOIN
[feature] ON fc_id_client = id_client AND fc_id_client <> 20
WHERE
fc_id_client = 1
but it is not working.
SELECT *
FROM
[client]
INNER JOIN
[feature_client] ON
client.id_client = feature_client.fc_id_client
INNER JOIN
[feature] ON
feature_client.fc_id_feature = feature.id_feature
WHERE
fc_id_feature = 1 AND
id_client NOT IN
(
SELECT fc_id_client
FROM
feature_client
INNER JOIN
feature ON
fc_id = id_feature
WHERE id_feature = 8
)

Aggregate sum on two columns in the same table

I am querying a data warehouse (so I cannot redesign tables), I'll do my best to mimic the scenario in a simple example.
We have 3 main tables for incident, change, and release. These 3 are connected through an intermediate table called intermediate. Here is their structure along with sample data:
Incident Table:
Change Table:
Release Table:
Intermediate Table:
The first 3 tables have exact same structure, but the intermediate table holds connection of these 3 tables pairwise. For example, if Rel1 is connected to Chg1, you have a row in the intermediate table as or . These two rows have no difference and may not co-exist.
QUERY:
I want ALL release records along with number of related incidents and number of related changes. Here is how I achieved this:
WITH SourceTable AS(
SELECT R.ReleaseItem, R.Prop1, R.Prop2 , I.RelOrInc2 as [RelatedIncident] , Null as [RelatedChanges] FROM Release R
LEFT JOIN [Intermediate] I
ON R.ReleaseItem = I.RelOrInc1
WHERE SUBSTRING(I.RelOrInc2,1,3) = 'Inc'
UNION
SELECT R.ReleaseItem, R.Prop1, R.Prop2 , I.RelOrInc1 , Null as [RelatedChanges] FROM Release R
LEFT JOIN [Intermediate] I
ON R.ReleaseItem = I.RelOrInc2
WHERE SUBSTRING(I.RelOrInc1,1,3) = 'Inc'
UNION
SELECT R.ReleaseItem, R.Prop1, R.Prop2 , Null as [RelatedIncident] , I.RelOrInc2 as [RelatedChanges] FROM Release R
LEFT JOIN [Intermediate] I
ON R.ReleaseItem = I.RelOrInc1
WHERE SUBSTRING(I.RelOrInc2,1,3) = 'Chg'
UNION
SELECT R.ReleaseItem, R.Prop1, R.Prop2 , Null as [RelatedIncident] , I.RelOrInc1 as [RelatedChanges] FROM Release R
LEFT JOIN [Intermediate] I
ON R.ReleaseItem = I.RelOrInc2
WHERE SUBSTRING(I.RelOrInc1,1,3) = 'Chg'
)
SELECT REL.* , COUNT(S.RelatedIncident) As [No Of Related Incidents] , COUNT(S.[RelatedChanges]) AS [No of Related Changes] FROM Release REL
LEFT JOIN SourceTable S
ON REL.ReleaseItem = S.ReleaseItem
GROUP BY REL.ReleaseItem, REL.Prop1, REL.Prop2
This query gives me my required result:
But I think my way of handling this query is so naive and not efficient. My data warehouse may contain around millions of records in intermediate table and my approach could be too slow.
Question:
Is there any better way to get such result with better performance?
BTW, I am using MS SQL Server 2012
SELECT
R.ReleaseItem, R.Prop1, R.Prop2,
[No Of Related Incidents] = (SELECT COUNT(*) FROM [Intermediate] i
WHERE (i.RelOrInc1 = r.ReleaseItem AND i.RelOrInc2 LIKE 'Inc%')
OR (i.RelOrInc2 = r.ReleaseItem AND i.RelOrInc1 LIKE 'Inc%')),
[No of Related Changes] = (SELECT COUNT(*) FROM [Intermediate] i
WHERE (i.RelOrInc1 = r.ReleaseItem AND i.RelOrInc2 LIKE 'Chg%')
OR (i.RelOrInc2 = r.ReleaseItem AND i.RelOrInc1 LIKE 'Chg%'))
FROM Release R
I think this will work for you. Can not say anything about performance. You should check.
select r.releaseitem,
r.prop1,
r.prop2,
sum(case when t.relorinc2 like 'inc%' then 1 else 0 end) as incidents,
sum(case when t.relorinc2 like 'chg%' then 1 else 0 end) as changes
from (select relorinc1, relorinc2 from intermediate where relorinc1 like 'rel%'
union all
select relorinc2, relorinc1 from intermediate where relorinc2 like 'rel%')t
join release r on t.relorinc1 = r.releaseitem
group by r.releaseitem, r.prop1, r.prop2

Insert Statement Error Message

Good Morning All
My boss helped me design a query where it populates 1.37 million lines of random data, he has now asked me to insert/update the results into a blank table. But for some reason I cannot get it to work.
The three columns are ArrivalDate, PitchType_Skey and Site_Skey. But when I run my query (See below) I get an error message and I don't know why. Can you help?
Msg 121, Level 15, State 1, Line 2
The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns.
Query:
USE Occupancy
INSERT INTO Bookings (ArrivalDate, Site_Skey, PitchType_Skey)
SELECT
Time.Date, Site.Site_Skey, Site.SiteWeighting, PitchType.PitchType_Skey,
PitchType.PitchTypeWeighting,
RAND(checksum(NEWID())) * Site.SiteWeighting * PitchType.PitchTypeWeighting AS Expr1
FROM
Capacity
INNER JOIN
Site ON Capacity.Site_Skey = Site.Site_Skey
INNER JOIN
PitchType ON Capacity.PitchType_Skey = PitchType.PitchType_Skey
INNER JOIN
Time
INNER JOIN
AGKey ON Time.ArrivalDayWeighting = AGKey.[Key] ON Capacity.StartDate <= Time.Date AND Capacity.EndDate >= Time.Date
CROSS JOIN
(SELECT 0 AS col1
UNION ALL
SELECT 1 AS col1) AS aaav
WHERE
(Time.CalendarYear = 2010)
AND (RAND(checksum(NEWID())) * Site.SiteWeighting * PitchType.PitchTypeWeighting >= 1.22)
Thanks
Wayne
The error message give you the answer. You have more items in your SELECT list (6)
Time.Date
Site.Site_Skey
Site.SiteWeighting
PitchType.PitchType_Skey
PitchType.PitchTypeWeighting
RAND(checksum(NEWID())) * Site.SiteWeighting * PitchType.PitchTypeWeighting AS Expr1
Than you do in your INSERT list (3)
ArrivalDate
Site_Skey
PitchType_Skey
Either remove some columns from your SELECT list or add some to your INSERT list.
As you haven't given the complete structure of your Bookings table I can only guess that you will need to do this
USE Occupancy
INSERT INTO Bookings
(
ArrivalDate,
Site_Skey,
PitchType_Skey
)
SELECT
Time.Date,
Site.Site_Skey,
PitchType.PitchType_Skey
FROM
Capacity
INNER JOIN Site ON Capacity.Site_Skey = Site.Site_Skey
INNER JOIN PitchType ON Capacity.PitchType_Skey = PitchType.PitchType_Skey
INNER JOIN Time
INNER JOIN AGKey ON Time.ArrivalDayWeighting = AGKey.[Key] ON Capacity.StartDate <= Time.Date AND Capacity.EndDate >= Time.Date
CROSS JOIN
(
SELECT 0 AS col1
UNION ALL
SELECT 1 AS col1
) AS aaav
WHERE
Time.CalendarYear = 2010
AND (RAND(checksum(NEWID())) * Site.SiteWeighting * PitchType.PitchTypeWeighting >= 1.22)
I have found the solution and I cant believe how easy it was, I just un-ticked the boxes I didn't want on the Query Designer.

Resources