How to use RIGHT OUTER JOIN with GROUP BY in SQl Server 2017? - sql

i want use ROJ in sql server with filter date but not work, i mean must return data table round null but not return how to fix problem ?
SQL Code
SELECT Lines.Target, COUNT(Round.ID) AS cnt
FROM Round RIGHT OUTER JOIN Line as Lines
on Round.Line = Lines.ID
WHERE Lines.Company = 20 AND
CAST(Round.System_Date AS DATE) BETWEEN
CAST('2019-03-01' AS DATE) AND CAST('2019-03-01' AS DATE)
GROUP BY Lines.Target
with out filter date code work
Must return =>
Target cnt
------ -----
7 0
9 0
15 0

Switch to LEFT JOIN. Move outer table condition from WHERE to ON to get true outer join result:
SELECT Lines.Target, COUNT(Round.ID) AS cnt
FROM Line as Lines
LEFT OUTER JOIN Round
on Round.Line = Lines.ID
AND CAST(Round.System_Date AS DATE) BETWEEN
CAST('2019-03-01' AS DATE) AND CAST('2019-03-01' AS DATE)
WHERE Lines.Company = 20
GROUP BY Lines.Target

Theres no BETWEEN required as its the same date you are searching for and make sure record exists for that specific date
Plus,
If you want the rounds table data being the master table then why you are using right outer join use Left Outer Join

Related

SQL statement return matching records from join and null records from join

I have a db with records like the following structure in the table;
id,msg,date,fid
19 ,"start","2012-02",NULL
20 ,"end","2012-03",19
21 , "start",2012-04,NULL
I have and entire db set up like this where the fid in some cases matches the id of another record. Id like to return all records that have matching start and end dates and just the start date if it doesn't have a corresponding end date fid like below:
19 ,"start","2012-02","end","2012-03"
21 , "start,"2012-04,"",NULL
I think you want a left join:
select t.fid, t.date as start_date, tf.date as end_date
from t left join
t tf
on tf.id = t.fid
where t.msg = 'start'
This assumes that there are only two types of records and fid is always non-NULL for 'end' records.
You just need a LEFT OUTER JOIN to your table. You can use an alias to refer to each instance:
SELECT startdt.id, startdt.msg, startdt.date, enddt.msg, enddt.date
FROM yourtable as startdt
LEFT OUTER JOIN yourtable as enddt
ON startdt.fid = enddt.id
AND enddt.msg = 'end'
WHERE startdt.msg = 'start'

sql server count from different table if not all rows exists

Im trying to get results from 2 tables. The first table there is the Ids with info, from the 2nd table I want to count existing for each id from the 1st table based on some condition. here is my code:
SELECT p.stId, count(att.adate)
FROM payments p
LEFT JOIN Attendence att ON att.stId = p.stId
where p.cyear = 2018 and p.cmonth = 3 and p.cId = 10
and att.adate between '2018/03/01' and '2018/03/30 23:59:59.999' and att.cid
= 10
GROUP BY p.stId
from the first table(p) I have 3 ids. but when I run this it returns only 1 id. the ids that not exists in the 2nd table (t) it does NOT give any results. what I want to do is that if there is no id in the 2nd table, I want to return a 0 for the count (count(att.adate))
Thanks.
Move the right side table conditions from WHERE to ON to get true left join result:
SELECT p.stId, count(att.adate)
FROM payments p
LEFT JOIN Attendence att ON att.stId = p.stId
and att.adate between '2018/03/01' and '2018/03/30 23:59:59.999' and att.cid
= 10
where p.cyear = 2018 and p.cmonth = 3 and p.cId = 10
GROUP BY p.stId
(When in WHERE, you get regular inner join result.)
You are probably missing the results because in your where clause you have conditions for columns in the Attendance table. For cases where there is no match with the payments table these values will be NULL. So I would have your query like this:
SELECT p.stId, count(att.adate)
FROM payments p
LEFT JOIN Attendence att ON att.stId = p.stId
where p.cyear = 2018 and p.cmonth = 3 and p.cId = 10
and (att.adate between '2018/03/01' and '2018/03/30 23:59:59.999' OR att.adate IS NULL) and (att.cid
= 10 or att.cid IS NULL)
GROUP BY p.stId
Your problem is that the where turns the left join into an inner join. I also want to simplify the date arithmetic:
SELECT p.stId, count(a.adate)
FROM payments p LEFT JOIN
Attendence a
ON a.stId = p.stId AND a.cid = p.cid AND
a.adate >= '2018-03-01' AND
a.adate < '2018-04-01
WHERE p.cyear = 2018 and p.cmonth = 3 and p.cId = 10
GROUP BY p.stId;
What the the changes that I've made:
Moved the filtering conditions on the second table to the ON clause. That is how LEFT JOINs work.
I added a JOIN condition on cid, so the comparison to 10 only occurs once (in the WHERE clause).
Changed the date format to YYYY-MM-DD. That is consistent with ISO 8601 standard date formats.
Changed the BETWEEN to >= and < -- I just don't want to think about milliseconds when I'm constructing date ranges at the month level.
A great place to understand why not to use BETWEEN with date/times is Aaron Bertrand's blog What do BETWEEN and the Devil Have In Common.

SQL Inner Join and nearest row to date

I dont't get it. I changed some of the code. In the WPLEVENT Table are a lot of Events per person. In the Persab-Table are the Persons with their History. Now I need the from the Persab Table just that row wich matches the persab.gltab Date nearest to the WPLEVENT.vdat Date. So all rows from the WPLEVENT, but just the one matching row from the PERSAB-Table.
SELECT
persab.name,
persab.vorname,
vdat,
eventstart,
persab.rc1,
persab.rc2
FROM wplevent
INNER JOIN
persab ON WPLEVENT.PersID = persab.PRIMKEY
INNER JOIN
(SELECT TOP 1 persab.rc1
FROM PERSAB
WHERE persab.gltab <= getdate() --/ Should be wplevent.vdat instead of getdate()
) NewTable ON wplevent.persid = persab.primkey
WHERE
persid ='100458'
ORDER BY vdat DESC
Need to use the MAX() function with the proper syntax by supplying an expression like MAX(persab.rc1). Also need to use GROUP BY for the second column rc2 in the subquery (although it looks like you do not need it). Finally you are missing the ON clause for the final INNER JOIN. I can update the answer to fix the query if you provide that information.
SELECT
Z1PERS.NAME
, Z1PERS.VORNAME
, WPLEVENT.VDat
, WPLEVENT.EventStart
, WPLEVENT.EventStop
, WPLEVENT.PEPGROUP
, Z1SGRP.TXXT
, PERSAB.GLTAB
, Z1PERS.PRIMKEY AS Expr1
, PERSAB.PRIMKEY
FROM
Z1PERS
INNER JOIN
WPLEVENT ON Z1PERS.PRIMKEY = WPLEVENT.PersID
INNER JOIN
Z1SGRP ON WPLEVENT.PEPGROUP = Z1SGRP.GRUPPE
INNER JOIN
(
SELECT MAX(Persab.rc1) --Fixed MAX expression
, persab.rc2
FROM
persab
GROUP BY
persab.rc2 --Need to group on rc2 if you want that column in the query otherwise remove this AND the rc2 column from select list
WHERE
WPLEVENT.PersID = PERSAB.PRIMKEY
AND WPLEVENT.VDat <= PERSAB.GLTAB
) --Missing ON clause for the INNER JOIN here
WHERE z1pers.vorname = 'henning'

Why left join is not giving distinct result?

I have following sql query and my left join is not giving me distinct result please help me to trace out.
SELECT DISTINCT
Position.Date,
Position.SecurityId,
Position.PurchaseLotId,
Position.InPosition,
ISNULL(ClosingPrice.Bid, Position.Mark) AS Mark
FROM
Fireball_Reporting.dbo.Reporting_DailyNAV_Pricing POSITION WITH (NOLOCK, READUNCOMMITTED)
LEFT JOIN Fireball.dbo.AdditionalSecurityPrice ClosingPrice WITH (NOLOCK, READUNCOMMITTED) ON
ClosingPrice.SecurityID = Position.PricingSecurityID AND
ClosingPrice.Date = Position.Date AND
ClosingPrice.SecurityPriceSourceID = #SourceID AND
ClosingPrice.PortfolioID IN (5,6)
WHERE
DatePurchased > #NewPositionDate AND
Position.Date = #CurrentPositionDate AND
InPosition = 1 AND
Position.PortfolioId IN (
SELECT
PARAM
FROM
Fireball_Reporting.dbo.ParseMultiValuedParameter(#PortfolioId, ',')
) AND
(
Position > 1 OR
Position < - 1
)
Now here in above my when I use LEFT JOIN ISNULL(ClosingPrice.Bid, Position.Mark) AS Mark and LEFT JOIN it is giving me more no of records with mutiple portfolio ids
for e.g . (5,6)
If i put portfolioID =5 giving result as 120 records
If i put portfolioID =6 giving result as 20 records
When I put portfolioID = (5,6) it should give me 140 records
but it is giving result as 350 records which is wrong . :(
It is happening because when I use LEFT JOIN there is no condition of PurchaseLotID in that as table Fireball.dbo.AdditionalSecurityPrice ClosingPrice not having column PurchaseLotID so it is giving me other records also whoes having same purchaseLotID's with diferent prices .
But I dont want that records
How can I eliminate those records ?
You get one Entry per DailyLoanAndCashPosition.PurchaseLotId = NAVImpact.PurchaseLotId
which would mean you must have more entrys in with the same PurchaseLotId
The most likely cause is that the left join produces duplicated PurchaseLotIds. The best way to know if if you perform a select distinct(PurchaseLotId) on your left side of the inner join.

Filtering SQL query by unique id and earliest dates that are in the future

I have this query that returns the correct data, but I would like to filter it.
SELECT TOP (100) PERCENT dbo.Reg_Master.id, dbo.Cart_Programs.cartid, dbo.Reg_Master.F_ID, dbo.BlockPeriod.profileid, dbo.Reg_Master.FirstName,
dbo.Reg_Master.LastName, dbo.BlockPeriod.startdate, dbo.Cart_Programs.blockid
FROM dbo.Cart_Programs LEFT OUTER JOIN
dbo.Reg_Master ON dbo.Cart_Programs.cartid = dbo.Reg_Master.cartid LEFT OUTER JOIN
dbo.BlockPeriod ON dbo.Cart_Programs.blockid = dbo.BlockPeriod.id
WHERE (dbo.BlockPeriod.profileid = xxx) AND (dbo.Reg_Master.F_ID = xxxx)
ORDER BY dbo.BlockPeriod.startdate
For each dbo.Reg_Master.id, I would like to return only the earliest dbo.BlockPeriod.startdate (that is today or later - in other words ignoring dates that have already passed) for each dbo.Reg_Master.id, I cannot seem to get it formatted correctly.
First of all, TOP 100 Percent does nothing, the optimizer will just ignore it.
Also, your left joins do not serve any purpose because your WHERE condition, so I have edited the SQL to use an inner join + cross apply vs an outer join + outer apply.
If I understand you correctly for each Reg_Master record, you want at most 1 record from BlockPeriod, where that 1 record is the closest date that is greater than today's date.
If so, then what you are looking for is an APPLY table operator combined with TOP (1) as shown below:
UPDATED:
SELECT Reg_Master.id,
Cart_Programs.cartid,
Reg_Master.F_ID,
T.profileid,
Reg_Master.FirstName,
Reg_Master.LastName,
T.startdate,
Cart_Programs.blockid
FROM Cart_Programs
JOIN Reg_Master ON Cart_Programs.cartid = Reg_Master.cartid
CROSS APPLY(
SELECT TOP 1 * FROM BlockPeriod
WHERE BlockPeriod.id = Cart_Programs.blockid
AND BlockPeriod.profileid = xxx AND Reg_Master.F_ID = xxxx
AND BlockPeriod.startdate >= GETDATE()
ORDER BY BlockPeriod.startdate ASC
) AS T