How to rewrite legacy join syntax *= in SQL Server - sql-server

I am trying to rewrite legacy join syntax with new standards.
SELECT count(*)
FROM es_dbo.tablTypes t
,es_dbo.tablReg r
,es_dbo.tabl_PRGandCLI p
WHERE t.ClientType *= r.ClientType
AND p.ID IN (
SELECT DISTINCT ClientID
FROM esinet_dbo.tablReG
)
AND t.ClientType IN (#intClientType)
Here is what I am trying.
SELECT count(*)
FROM es_dbo.tablTypes t
LEFT JOIN es_dbo.tablReg r ON t.ClientType = r.ClientType
LEFT JOIN es_dbo.tabl_PRGandCLI p ON p.ID IN (
SELECT DISTINCT ClientID
FROM es_dbo.tablReG
)
I am getting same no of records whether I use LEFT JOIN or INNER JOIN in 2nd part of query. Can anyone explain

Try the following:
SELECT count(*)
FROM es_dbo.tablTypes t
left join es_dbo.tablReg r on t.ClientType = r.ClientType
WHERE t.ClientType IN (#intClientType)
EXISTS (SELECT 1 FROM esinet_dbo.tablReG p WHERE r.ClientID = p.ID)
1) I assumed #intClientType is a scalar value, so no need for IN
2) removed DISTINCT and subquery as you check for existence. EXISTS should be faster as it involves finding the first element, rather than doing some sorting for DISTINCT.
3) *= was replaced with LEFT JOIN, based on discussion from here.

It is neither inner join nor left join according to query it seems like cross join so you can use following query:
SELECT count(*)
FROM es_dbo.tablTypes t
LEFT JOIN es_dbo.tablReg r ON t.ClientType = r.ClientType,
es_dbo.tabl_PRGandCLI p WHERE p.ID IN (
SELECT DISTINCT ClientID
FROM es_dbo.tablReG
)

Related

Multiple Nested Inner Joins: not all records are shown

I have difficulty joining two tables that look like the following:
The main table PMEOBJECT which has a unique key named OBJECTID and
has in total 12768 rows.
Then I want to join PMEOBJECTVALIDITY on it which has an n:1 relationship with PMEOBJECT, since it has more rows,
because it saves the changes over time of PMEOBJECT (i.e. when a certain object is not
valid anymore), this one has 12789 rows (meaning only 21 objects
changed over time). However, I only want to have the current last
VALIDFROM date shown in the query. This all works fine.
Then the trouble starts when I want to join PMEOBJECTDIMENSION, which has an
n:1 relationship with PMEOBJECTVALIDITY and has 36737 rows in total.
SELECT
PMEOBJECT.OBJECTID
,PMEOBJECTVALIDITY.VALIDFROM
,PMEOBJECTDIMENSION.DIMENSION2_
FROM PMEOBJECT
LEFT JOIN PMEOBJECTVALIDITY
ON PMEOBJECTVALIDITY.OBJECTID = PMEOBJECT.OBJECTID
AND PMEOBJECTVALIDITY.DATAAREAID = PMEOBJECT.DATAAREAID
INNER JOIN(
SELECT
OBJECTID,
MAX(VALIDFROM) AS NEWFROMDATE,
MAX(VALIDTO) AS NEWTODATE
FROM PMEOBJECTVALIDITY B
GROUP BY OBJECTID
) B
ON PMEOBJECTVALIDITY.OBJECTID = B.OBJECTID
AND PMEOBJECTVALIDITY.VALIDFROM = B.NEWFROMDATE
LEFT JOIN PMEOBJECTDIMENSION
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND PMEOBJECTDIMENSION.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID
INNER JOIN(
SELECT
OBJECTVALIDITYID,
MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
Results in query per step:
SELECT PMEOBJECT: 12768 rows
LEFT JOIN PMEVALIDITY: 12789 rows
INNER JOIN PMEVALIDITY: 12768 rows
LEFT JOIN PMEOBJECTDIMENSION: 36737 rows
INNER JOIN PMEOBJECTDIMENSION: 12729 rows
I want the end result again to have the same 12768 rows, I don't want any ObjectId to be left out.
What am I missing here?
Kind regards,
Igor
Following might help:
from PMEOBJECTDIMENSION onwards:
LEFT JOIN (SELECT PMEOBJECTDIMENSION.OBJECTVALIDITYID, PMEOBJECTDIMENSION.DATAAREAID
FROM PMEOBJECTDIMENSION
INNER JOIN(SELECT OBJECTVALIDITYID, MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
)X
ON X.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND X.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID
and select the distinct records if duplicates present.
The INNER JOINs are filtering out records- what you want is that the LEFT JOIN table (PMEOBJECTVALIDITY and PMEOBJECTDIMENSION) should only include records that have at least a match on the INNER JOIN queries (alias B and C). You can accomplish this with by nesting the INNER JOIN with the LEFT JOIN, generally done as follows:
SELECT *
FROM A
LEFT JOIN B
INNER JOIN C
ON B.ID = C.BID
ON A.ID = B.AID
Now B is INNER JOINed on C and will only contain records that have a match in C, but will preserve the LEFT JOIN not remove any records from A.
In your case, you can simply move the ON clause from the LEFT JOIN to the end of the following INNER JOIN.
SELECT
PMEOBJECT.OBJECTID
,PMEOBJECTVALIDITY.VALIDFROM
,PMEOBJECTDIMENSION.DIMENSION2_
FROM PMEOBJECT
LEFT JOIN PMEOBJECTVALIDITY
INNER JOIN(
SELECT
OBJECTID,
MAX(VALIDFROM) AS NEWFROMDATE,
MAX(VALIDTO) AS NEWTODATE
FROM PMEOBJECTVALIDITY B
GROUP BY OBJECTID
) B
ON PMEOBJECTVALIDITY.OBJECTID = B.OBJECTID
AND PMEOBJECTVALIDITY.VALIDFROM = B.NEWFROMDATE
ON PMEOBJECTVALIDITY.OBJECTID = PMEOBJECT.OBJECTID
AND PMEOBJECTVALIDITY.DATAAREAID = PMEOBJECT.DATAAREAID --here it is!
LEFT JOIN PMEOBJECTDIMENSION
INNER JOIN(
SELECT
OBJECTVALIDITYID,
MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND PMEOBJECTDIMENSION.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID --I'm here

Select row with max value in multiple where condition

I edited the following query based on this page:
Selecting a Record With MAX Value
Select query :
select
Users.Id, Users.[Name], Users.Family, Users.BirthDate,
Users.Mobile, Users.[Description], Users.Email,
Users.UserName, Users.fatherName,
Users.archiveNumber, Users.[Address], Users.IsMarried,
Users.Mazhab,
Cities.CityName, Religions.PersianName, Users.Date_insert,
Users.ImageName,
MaghtaeTahsilis.[Name] as MaghtaeTahsilisName,
FieldStudies.[Name] as FieldStudiesName,
Eductionals.Institute, Eductionals.Moaddal,
Eductionals.FromYear, Eductionals.ToYear
from
Users
left outer join
Eductionals on Users.id = Eductionals.UserID
left outer join
MaghtaeTahsilis on Eductionals.MaghtaeID = MaghtaeTahsilis.ID
left outer join
Cities on Users.City_Id = Cities.Id
left outer join
Religions on Users.Relegion_ID = Religions.ID
left outer join
FieldStudies on Eductionals.FieldStudy_ID = FieldStudies.ID
where
Users.UserName = #code_melli
and Eductionals.MaghtaeID = (select MAX(MaghtaeID) from Eductionals
where Eductionals.UserID = Users.Id)
This command works correctly in choosing MAX value, But if the following statement has a NULL value, no row are returned. I want to show NULL value if it is NULL.
Your left outer joins are being turned into inner joins by the where conditions. Your query should look like:
select u.Id, u.[Name], u.Family, u.BirthDate, u.Mobile, u.[Description], u.Email, u.UserName, u.fatherName,
u.archiveNumber, u.[Address], u.IsMarried, u.Mazhab, c.CityName, r.PersianName, u.Date_insert, u.ImageName,
mt.[Name] As MaghtaeTahsilisName, fs.[Name] As FieldStudiesName, e.Institute, e.Moaddal, e.FromYear, e.ToYear
from Users u left outer join
Eductionals e
on u.id = e.UserID and
e.MaghtaeID = (select MAX(e2.MaghtaeID)
from Eductionals e2
where e2.UserID = u.Id
) left outer join
MaghtaeTahsilis mt
on e.MaghtaeID = mt.ID left outer join
Cities c
on u.City_Id = c.Id left outer join
Religions r
on u.Relegion_ID = r.ID left outer join
FieldStudies fs
on e.FieldStudy_ID = fs.ID
where u.UserName = #code_melli ;
Conditions on the first table -- in a chain of left joins should be in the where clause. On subsequent tables in the on clauses.
You'll notice that I also added table aliases so the query is easier to write and to read.
You can also use window functions:
from Users u left outer join
(select e2.*,
row_number() over (partition by e2.userId order by e2.MaghtaeID desc) as seqnum
from Eductionals e2
) e
on u.id = e.UserID and
e.seqnum = 1 left outer join
. . .
Reason for returning zero records when second query returns NULL is, when second query returns NULL, your SQL syntax become like this
And Eductionals.MaghtaeID=NULL
And probably Dbtable Educationals holds NULL values for field MaghtaeID.
So SQL fails above syntax and thus returns zero records.
Correct syntax for checking NULL values would be
And Eductionals.MaghtaeID is NULL
So please modify where condition in your query as follows which will return desired result.
where Users.UserName = #code_melli AND isnull(Eductionals.MaghtaeID,0) = isnull((select MAX(MaghtaeID) from Eductionals where Eductionals.UserID = Users.Id),0)

How can I efficiently use join and pivot in my SQL code

I have 3 tables. The query returned the desired result just the sorting of records. I added Order By but it did not work.
Result should be:
I got the result it is just the sorting of records. I want to order by the ID but it is not working.
QUERY:
WITH NAMES AS (
SELECT
P.NAMES,
P.CODE,
Q.NUM_TYP,
Q.PHONE_NUM
FROM
dbo.NAMES P
INNER JOIN dbo.PHONE Q
ON P.ID = Q.ID
LEFT JOIN DBO.ADDRESS S
ON P.PRSN_IK = S.PRSN_IK
WHERE S.ADDR Is Null
)
SELECT *
FROM
NAMES
PIVOT (Max(PHONE_NUM) FOR NUM_TYP IN (WORK, HOME)) R;
Appreciate any input. Thanks.
try trhis :
select f1.Name, nullif(f1.code, '') Code ,
isnull(f2.phone_num, 'N/A') work_phone_num, isnull(f3.phone_num, 'N/A') home_phone_num
from Names f1
left outer join Phone f2 on f1.id=f2.id and f2.Num_type='WORK'
left outer join Adress f2b on f2.id=f2b.id and f2.num_type=f2b.add_type
left outer join Phone f3 on f1.id=f3.id and f3.Num_type='HOME'
left outer join Adress f3b on f3.id=f3b.id and f3.num_type=f3b.add_type
where f2b.id is null or f3b.id is null
given that your query is working, this should work :
;WITH NAMES AS (
SELECT
P.NAMES,
P.CODE,
Q.NUM_TYP,
Q.PHONE_NUM
FROM dbo.NAMES P
INNER JOIN dbo.PHONE Q
ON P.ID = Q.ID
LEFT JOIN DBO.ADDRESS S
ON P.PRSN_IK = S.PRSN_IK
WHERE S.ADDR Is Null
), PIVOTED
AS
(
SELECT *
FROM NAMES
PIVOT (Max(PHONE_NUM) FOR NUM_TYP IN (WORK, HOME)) R
)
SELECT * FROM PIVOTED piv
inner join [dbo].[NAMES] nam
on piv.names = nam.names
ORDER BY nam.ID
I have included P.ID and wrapped everything under subquery.

Select only columns from joined tables from CTE

The following is my CTE:
;WITH CTE AS
(SELECT O.*, E.Num, E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT * FROM CTE -- gives results I want to join to
The following is the query that I want to SELECT from (and only use this SELECT statement for my query results:
SELECT
MU.Type
,MU.Num
,MU.MTBUR
,MF.MTBF
,MU.Hours
,MF.Hours
FROM
MUType_Stage MU
INNER JOIN
MFType_Stage MF
ON
MU.Type = MF.Type
AND
MU.Num = MF.Num
-- Need do JOIN to CTE right here
INNER JOIN
Status_STAGE S
ON
MU.Nu = S.Part
LEFT OUTER JOIN
RCN N
ON
N.Name = R.Part
LEFT OUTER JOIN
Repair RR
ON
R.ACSS_Name = RR.Name
So basically I need to JOIN to the CTE inside the SELECT query in which I want the results.
OR ALTERNATIVELY Uses this select statement to join to the CTE but only what the selected columns from the second select statement
Try this syntax
WITH CTE
AS (SELECT O.*,
E.Num,
E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT MU.Type,
MU.Num,
MU.MTBUR,
MF.MTBF,
MU.Hours,
MF.Hours
FROM MUType_Stage MU
INNER JOIN MFByACType_Stage MF
ON MU.Type = MF.Type
AND MU.Num = MF.Num
INNER JOIN CTE C --- JOIN HERE as like other tables
ON C.Num = MF.Num
INNER JOIN Status_STAGE S
ON MU.Nu = S.Part
LEFT OUTER JOIN RCN N
ON N.Name = R.Part
LEFT OUTER JOIN Repair RR
ON R.ACSS_Name = RR.Name

Use a calculated column in a where clause

I'm trying to use a calculated column in a where clause.
I've trying everything from CROSS APPLY, to sub-query select but it does not give me the anything near what I need.
My query so far:
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
WHERE Sales > 100
GROUP BY p.Code, c.AccountNumber, Sales
This does not work, as 'Sales' is an invalid column
Using Derived Columns in a predicate
You'll need to wrap the inner query in a derived table or CTE in order to be able to use derived columns in the WHERE clause (Also, note SUM() is specified just once, using the results of the multiplication):
SELECT x.Code, x.AccountNumber, x.Sales
FROM
(
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
) AS x
WHERE x.Sales > 100;
Repeating the Derived Column in a HAVING clause
As per #Jonny's comment, the other way is not to DRY up the calculated column, but to instead repeat the calculation. Use HAVING instead of WHERE after a GROUP BY has been applied.
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
HAVING SUM(p.UnitPrice * od.QtyShipped) > 100;
In either case, as per comments below, note that the calculated expression is SUM(p.UnitPrice * od.QtyShipped) and not SUM(p.UnitPrice) * SUM(od.QtyShipped).
You can use the common table expression for this
;WITH CTE AS
(
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sale
)
SELECT *
FROM CTE WHERE CTE.Sales>100
If it's a calculated column you can use "HAVING".
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sales
HAVING SALES > 100;

Resources