How to implement a SQL Server query which has several join conditions - sql

I am trying to implement this query but I can’t figure out why I am not getting the result.
Here are the descriptions:
Lets say I have a table call: TableAct
Acct# Date WithdrawAmt DepositAmt
!24455 2012-11-19-00.00.00 1245.77 200.50
125577 2011-02-12-00.00.00 100.98 578.00
Another table TableCustomerOrd:
ID# COrder# CustID Ord_Description VendorType
124455 7712AS 123 1AAA Permanent
125577 9914DL 346 1BBB Partial
... UK1234 111 2HJ5 Permanent'
,,, FR0912 567 5LGY Partial
Then TableCustomerDtls:
CustID Descriptions Delivery Address ZipCode
123 1AAA_BLUESHARE SUCCESSFUL 222 Main St 97002
346 1BBB_CHASE DECLINE 40 West Side 97122
111 2HJ5_CITIBANK SUCCESSFUL ……. …….
567 5LGY_VANGURD DECLINED ---- -----
And table DelivaryFlight:
FlightOrder# FlightCustID FlightDt
7712AS 123 2011-9-29-00.00.00
9914DL 346 2010-11-2-00.00.00
UK1234 111 2012-4-1-00.00.00
FR0912 567 2012-9-11-00.00.00
I want to update TableAct on the following conditions:
TableAct. Acct# = TableCustomerOrd.ID#, AND:
TableCustomerOrd. CustID = TableCustomerDtls.CustID and at the same time, TableCustomerOrd.Ord_Descriptions field should match with TableCustomerDtls. Descriptions field anything before “_” . Therefore ‘1AAA’, ‘2HJ5’ etc. AND:
DelivaryFlight.FlightOrder# = TableCustomerOrd.COrder#, AND: DelivaryFlight.FlightCustID = TableCustomerOrd. CustID. Also TableCustomerDtls. Delivery = ‘SUCCESSFUL’ AND:
DelivaryFlight.FlightOrder# = TableCustomerOrd. COrder#
AND DelivaryFlight.FlightCustID = TableCustomerOrd. CustID
Also TableCustomerDtls. Delivery = ‘DECLINED
Then I want to compare: elivaryFlight.FlightDt > DelivaryFlight.FlightDt.
Basically I need to match table DelivaryFlight columns FlightOrder#, FlightCustID with TableCustomerOrd.
Moreover TableCustomerDtls column Delivery to ck for delivary status such as ‘DECLINED’.
And ‘SUCCESSFUL’ condition and compare ‘SUCCESSFUL’ FlightDt with ‘DECLINED’ FlightDt.
Here's my query but please help me to understand, I am sure this could be done in a better way.
The query is not working:
Update
Set …
FROM TableAct AC
Join TableCustomerOrd CustOd
ON AC.Acct# = CustOd.ID#
Join TableCustomerDtls CDtls
ON CDtls. CustID = CustOd. CustID
AND (CustOd.Ord_Descriptions =
Left(CDtls.Descriptions, LEN(rtrim(CDtls.Descriptions))))
JOIN DelivaryFlight DF
ON DF.FlightOrder# = CustOd.COrder#
AND DF.FlightCustID = CustOd.CustID
AND CDtls.Delivery = ‘SUCCESSFUL’
JOIN DelivaryFlight DF2
ON DF2.FlightOrder# = DF.COrder#
AND DF2.FlightCustID = DF.CustID
AND CDtls.Delivery = ‘DECLINED’
WHERE DelivaryFlight. FlightDt > DelivaryFlight. FlightDt
AND DepositAmt > 100
Your Help will be monumental 'cause my project due end of this week.
Thank you

If I have a complex query like this, I start by creating a "simple" select which produces only the rows to be updated.
It should also return both the update values and the pk for the updated table
It is then (relatively) straight forward to (inner) join this with the table to be updated and do the update remebering to only update matching rows by including
WHERE tblTobeUpdated.pk = SimpleSelect.pk
Hope this helps

I don't have the time to look at this in depth but I suspect you at least want to fix:
WHERE DelivaryFlight. FlightDt > DelivaryFlight. FlightDt
This is a condition that can never be met.
You probably want:
WHERE DF. FlightDt > DF2. FlightDt
it is also useful with these complex queires for an update to be able to see the records that would be updated, so I usually do something like this:
Update
Set …
--Select *
FROM TableAct AC
Then instead of running the update, I run just highlight and run the part that starts with select to see the results and don't test the update until I am sure I am selecting the records I want to select and that the values I will be replacing are correct.

Try breaking your query down, heres a query I wrote today, test each part separately
SELECT
Employee
, Reference
, Payroll
, [Hours] / 60
[Hours]
, [Days]
FROM
(
SELECT
Employee
, Reference
, Payroll
, SUM( Duration ) AS [Hours]
, AvailableID
FROM
(
SELECT
RequirerID
, Duration
, RTRIM( COALESCE(MA.MemberLastName, '')
+ ' ' + COALESCE(MA.MemberFirstName, '')
+ ' ' + COALESCE(MA.MemberInitial, '')) Employee
, COALESCE(MA.Detailref1, '') Reference
, COALESCE(MA.PayrollRef, '') Payroll
, Available.AvailableId
FROM
(
SELECT DISTINCT
RequirerID
, ShiftDate
, CAST(ShiftStart - ShiftEnd - ShiftBreak AS DECIMAL(19,2)) ShiftDuration
, Id RequirementRecordID
FROM
Requirements
WHERE
Requirements.ShiftDate BETWEEN #ParamStartDate
AND #ParamEndDate
AND RequirerID IN (SELECT ID FROM MemberDetails WHERE CompanyID = #ParamCompanyID)
)
R
INNER JOIN
ShiftConfirmed
INNER JOIN
Available
INNER JOIN
MemberDetails MA
ON Available.AvailableID = MA.ID
ON ShiftConfirmed.AvailableRecordID = Available.ID
ON R.RequirementRecordID = ShiftConfirmed.RequirementRecordID
WHERE
R.ShiftDate BETWEEN #ParamStartDate
AND #ParamEndDate
AND COALESCE(ShiftChecked, 0) BETWEEN 0 AND 1
)
ShiftDay
Group By
Employee
, Reference
, Payroll
, AvailableId
) Shifts
INNER JOIN
(
SELECT
COUNT( * ) AS [Days]
, AvailableID
FROM
(
SELECT DISTINCT
R.ShiftDate
, Available.AvailableId
FROM
(
SELECT DISTINCT
ShiftDate
, Id RequirementRecordID
FROM
Requirements
WHERE
Requirements.ShiftDate BETWEEN #ParamStartDate
AND #ParamEndDate
AND RequirerID IN (SELECT ID FROM MemberDetails WHERE CompanyID = #ParamCompanyID)
)
R
INNER JOIN
ShiftConfirmed
INNER JOIN
Available
INNER JOIN
MemberDetails MA
ON Available.AvailableID = MA.ID
ON ShiftConfirmed.AvailableRecordID = Available.ID
ON R.RequirementRecordID = ShiftConfirmed.RequirementRecordID
WHERE
R.ShiftDate BETWEEN #ParamStartDate
AND #ParamEndDate
AND COALESCE(ShiftChecked, 0) BETWEEN 0 AND 1
)
ShiftDay
Group By
AvailableId
) D
ON Shifts.AvailableID = D.AvailableID
WHERE [Hours] > 0
ORDER BY
Employee

Related

How to get the most recent record of multiple of the same records in a table while joining another table?

SELECT tblSign.sigdate,tblSign.sigtime,tblSign.sigact,tblSign.esignature,tblEmpl.fname,tblEmpl.lname,tblEmpl.location, tblEmpl.estatus,tblLocs.unit,tblLocs.descript,TblLocs.addr1,tblLocs.city,tblLocs.state, tblLocs.zip
FROM tblEmpl
LEFT JOIN tblSign
ON tblSign.eight_id = tblEmpl.eight_id
AND tblSign.formid = '9648'
AND tblSign.sigact <> 'O'
AND tblSign.sigdate >= '2022-11-01'
LEFT JOIN tblLocs
ON tblEmpl.location = tblLocs.location
WHERE tblEmpl.estatus = 'A'
AND tblEmpl.location = '013'
ORDER BY
tblSign.sigdate ASC;
My table Sign has multiple records with the same eight_id so Im just trying to join tables getting the most recent record from tblSign besides multiple records
Data I get
Sigdate
fname
lname
location
sigact
2022-11-01
Bill
Lee
023
A
2022-10-01
Bill
Lee
023
A
2022-11-01
Carter
Hill
555
A
This is what I want :
Sigdate
fname
lname
location
sigact
2022-11-01
Bill
Lee
023
A
2022-11-01
Carter
Hill
555
A
Start by getting into better code-writing habits. Having all column names in one long string is horrible for readability and consequently troubleshooting. You can select the most recent record from a table by using a ROW_NUMBER function. I took your code, cleaned it up, added a derived table and in the derived table added a ROW_NUMBER function. I can't validate that the query works because you didn't post example source data from your tblEmpl, tblSign, and tblLocs tables. I'm not sure if the AND tblSign.sigact <> 'O' is valid in the derived table because it's not clear if you were trying to just limit the date range or that was your attempt to retrieve the most recent date.
SELECT
tblSign.sigdate
, tblSign.sigtime
, tblSign.sigact
, tblSign.esignature
, tblEmpl.fname
, tblEmpl.lname
, tblEmpl.location
, tblEmpl.estatus,tblLocs.unit
, tblLocs.descript
, TblLocs.addr1
, tblLocs.city
, tblLocs.state
, tblLocs.zip
FROM tblEmpl
LEFT JOIN (
SELECT *
--Used to order the records for each eight_id by the date.
--Most recent date for each eight_id will have row_num = 1.
, ROW_NUMBER() OVER(PARTITION BY eight_id ORDER BY sigdat DESC) as row_num
FROM tblSign as ts
WHERE tblSign.formid = '9648'
AND tblSign.sigact <> 'O'
AND tblSign.sigdate >= '2022-11-01' --Not clear if this is just to limit results or an attempt to get most recent date in the failed original code.
) as ts
ON ts.eight_id = tblEmpl.eight_id
AND ts.row_num = 1 --Use to limit to most recent date.
LEFT JOIN tblLocs
ON tblEmpl.location = tblLocs.location
WHERE tblEmpl.estatus = 'A'
AND tblEmpl.location = '013'
ORDER BY
tblSign.sigdate ASC
You use ROW_NUMBER to get the last entry in my case for every esignature, as i thought this must be unique
WITH CTE AS
(SELECT
tblSign.sigdate,
tblSign.sigtime,
tblSign.sigact,
tblSign.esignature,
tblEmpl.fname,
tblEmpl.lname,
tblEmpl.location,
tblEmpl.estatus,
tblLocs.unit,
tblLocs.descript,
TblLocs.addr1,
tblLocs.city,
tblLocs.state,
tblLocs.zip,
ROW_NUMBER() OVER(PARTITION BY tblSign.esignature ORDER BY tblSign.sigdate DESC) rn
FROM
tblEmpl
LEFT JOIN
tblSign ON tblSign.eight_id = tblEmpl.eight_id
AND tblSign.formid = '9648'
AND tblSign.sigact <> 'O'
AND tblSign.sigdate >= '2022-11-01'
LEFT JOIN
tblLocs ON tblEmpl.location = tblLocs.location
WHERE
tblEmpl.estatus = 'A'
AND tblEmpl.location = '013')
SELECT sigdate,
sigtime,
sigact,
esignature,
fname,
lname,
location,
estatus,
unit,
descript,
addr1,
city,
state,
zip
WHERE rn = 1
ORDER BY sigdate ASC;

show one row and sum values

I have a query to select invoices and their items from database. I have posted example down below with two invoices having 3 invoice items (I'm using linked servers from MSSQL to Oracle DB).
Example with cID 1616251758086 got 3 positions with same "Stawka VAT" so I would like to show only one row with "Stawka VAT" = 0.23000 but values in "Netto", "VAT", "Brutto" should be summed (commented code with SUM works fine but still shows 3 rows, each one with whole sum).
Example with cID 1616251238669 got 3 positions with different "Stawka VAT" values so it should show output like already does.
I tried bunch of things but with no proper result.
CURRENT CODE:
SELECT
invo.cID, -- ID dokumentu
cProcessID, -- Dane faktury ERP
cERPNumber, -- Dane z pola cProcessID
cERPStatus, -- Wartość zmienia się na 200 po pobraniu danych
invo.cType as 'Typ dok',
cINumberExternal as 'Nr dok',
(CASE WHEN invo.cType = 'creditmemo' THEN cReferencingInvoiceNr ELSE '' END) as 'Korekta',
cIDateExternal as 'Data wyst',
cDeliveryDate as 'Data dok',
cDateOfReceipt AS 'Data wpływu',
ISNULL(invo_items.cText, '') as 'Treść',
invo_items.cCurrency as 'Waluta',
ISNULL(cCurrencyRate, '') as 'Kurs',
invo_items.cIItemNumber as 'Pozycja faktury',
invo_items.cTaxRate as 'Stawka VAT',
invo_items.cNetTotalAmount as 'Netto',
invo_items.cTaxAmount as 'VAT',
invo_items.cNetTotalAmount+invo_items.cTaxAmount as 'Brutto',
--SUM(invo_items.cNetTotalAmount) OVER(Partition by invo_items.ciid, invo_items.cTaxRate) as 'Netto',
--SUM(invo_items.cTaxAmount) OVER(Partition by invo_items.ciid, invo_items.cTaxRate) as 'VAT',
--SUM(invo_items.cNetTotalAmount+invo_items.cTaxAmount) OVER(Partition by invo_items.ciid,invo_items.cTaxRate) as 'Brutto',
cBaselineDate as 'Termin płatności',
invo.cVendorID as 'VendorID',
cVendorVatnumber as 'VendorNIP',
CONCAT(kh.cname, '', kh.cname2) as 'VendorName',
kh.cStreet as 'Ulica',
kh.cCity as 'Miasto',
kh.cCountry as 'Kraj'
FROM ORACLE_OTTO..xxxxxx.INVOICES as invo
JOIN ORACLE_OTTO..xxxxxx.VENDORMASTERDATA as kh on kh.cvendorid = invo.cvendorid
JOIN ORACLE_OTTO..xxxxxx.INVOICEITEMS as invo_items on invo.cid = invo_items.ciid
WHERE invo.cID in ('1616251758086', '1616251238669')
CURRENT OUTPUT:
cID
Pozycja faktury
Stawka VAT
Netto
VAT
Brutto
1616251758086
1
0.23000
4.0000
0.9200
4.9200
1616251758086
2
0.23000
1500.0000
345.0000
1845.0000
1616251758086
3
0.23000
20981.0000
4825.6300
25806.6300
1616251238669
1
0.23000
465.2100
107.0000
572.2100
1616251238669
2
0.08000
112.2800
8.9800
121.2600
1616251238669
3
0.05000
152.6400
7.6300
160.2700
EXPECTED OUTPUT:
cID
Pozycja faktury
Stawka VAT
Netto
VAT
Brutto
1616251758086
1,2,3
0.23000
22485.0000
5171.5500
27656.5500
1616251238669
1
0.23000
465.2100
107.0000
572.2100
1616251238669
2
0.08000
112.2800
8.9800
121.2600
1616251238669
3
0.05000
152.6400
7.6300
160.2700
Maybe using a common table expression would help?
with cte as (
select .... -- your query from the question
)
select
cte.cID,
cte.cIItemnumber as 'Pozycja faktury',
cte.cTaxRate as 'Stawka VAT',
SUM(cte.cNetTotalAmount) as 'Netto',
SUM(cte.cTaxAmount) as 'VAT',
SUM(cte.cNetTotalAmount+cte.cTaxAmount) as 'Brutto'
from cte
group by cte.cID, cte.CIItemnumber,cte.cTaxRate
Did not try this out of course, but you will get my drift... :)
This one should do your job:
SELECT
invo.cID,
STUFF((
SELECT ', ' + CAST(i_qry.cIItemNumber AS varchar)
FROM ORACLE_OTTO..xxxxxx.INVOICEITEMS i_qry
WHERE invo.cid = i_qry.ciid
FOR XML PATH('')
), 1, 2, '') AS [Pozycja faktury],
invo_items.cTaxRate AS [Stawka VAT],
SUM(invo_items.cNetTotalAmount) AS [Netto],
SUM(invo_items.cTaxAmount) AS [VAT],
SUM(invo_items.cNetTotalAmount + invo_items.cTaxAmount) AS [Brutto]
FROM
ORACLE_OTTO..xxxxxx.INVOICES as invo
JOIN ORACLE_OTTO..xxxxxx.VENDORMASTERDATA as kh on kh.cvendorid = invo.cvendorid
JOIN ORACLE_OTTO..xxxxxx.INVOICEITEMS as invo_items on invo.cid = invo_items.ciid
GROUP BY
invo.cID, invo_items.cTaxRate
In this case I assume that ORACLE_OTTO..xxxxxx.INVOICESITEMS.cIItemNumber is a number. In case it is a char/varchar, just remove the CAST around it.

Bizarre Join with comma

I'm looking at someone else's code and find this bizarre join:
SELECT
SUM(
(
intUnitOverheadCost + intUnitLaborCost + intUnitMaterialCost + intUnitSubcontractCost
+ intUnitDutyCost + intUnitFreightCost + intUnitMiscCost
)
*
(
(
CASE
WHEN imtSource = 3
THEN - 1
ELSE 1
END
) * intQuantity
)
)
FROM PartTransactions --imt
INNER JOIN PartTransactionCosts --int
ON imtPartTransactionID = intPartTransactionID
LEFT JOIN Warehouses --imw
ON imtPartWarehouseLocationID = imwWarehouseID
, ProductionProperties --xap <-- weird join
WHERE imtJobID = jmpJobID
AND imtSource IN (2,3)
AND imtReceiptID = ''
AND Upper(imtTableName) <> 'RECEIPTLINES'
AND imtNonInventoryTransaction <= {?CHECKBOXGROUP_4_ShowNonInventory}
AND imtJobType IN (1, 3)
AND imtTransactionDate < DATEADD(d, 1, {?PROMPT_1_TODATE})
AND (
imtNonNettable = 0
OR (
imtNonNettable <> 0
AND ISNULL(imwDoNotIncludeInJobCosts, 0) = 0
)
)
AND intCostType = (
CASE -- Always 1
WHEN xapIMCostingMethod = 1
THEN 1
WHEN xapIMCostingMethod = 2
THEN 2
WHEN xapIMCostingMethod = 3
THEN 3
ELSE 4
END
)
There is only one record in table ProductionProperties and the result of select xapIMCostingMethod from ProductionProperties is always 1.
There are always 4 enumerated results in PartTransactionCosts, but only 1 result is allowed.
ProductionProperties.xapIMCostingMethod is implicitly joining to PartTransactionCosts.intCostType
My specific question is what is really going on with this comma join? It looks like it has to be a cross-join, later filtered in the WHERE clause with one possible result.
Agree with the previous answer. It is a cartesian join but since the rows are 1 it doesn't cause an issue.
I'm thinking if you added rows to ProductionProperties then it would serve as a multiplier for your sum. I did a little experiment to show the issue:
declare #tableMoney table (
unit int,
Product char(5),
xapIMPCostingMethod int,
Cost money
)
declare #tableProdProperties table (
xapIMPCostingMethod int
)
insert #tableMoney (unit, Product, xapIMPCostingMethod, Cost)
values
(1,'bike',1, 2.00),
(1,'car',1, 2.25),
(2,'boat',2, 4.50)
insert #tableProdProperties (xapIMPCostingMethod)
values (1),
(2)
select sum(Cost)
from #tableMoney, #tableProdProperties
I also don't like to use joins where it isn't clear what is joining to what so I always use an alias:
select sum(Cost)
from #tableMoney tbm join #tableProdProperties tpp
on tbm.xapIMPCostingMethod = tpp.xapIMPCostingMethod

How to add a count/sum and group by in a CTE

Just a question on displaying a row on flight level and displaying a count on how many crew members on that flight.
I want to change the output so it will only display a single record at flight level and it will display two additional columns. One column (cabincrew) is the count of crew members that have the 'CREWTYPE' = 'F' and the other column (cockpitcrew) is the count of crew members that have the `'CREWTYPE' = 'C'.
So the query result should look like:
Flight DepartureDate DepartureAirport CREWBASE CockpitCrew CabinCrew
LS361 2016-05-19 BFS BFS 0 3
Can I have a little help tweaking the below query please:
WITH CTE AS (
SELECT cd.*, c.*, l.Carrier, l.FlightNumber, l.Suffix, l.ScheduledDepartureDate, l.ScheduledDepartureAirport
FROM
(SELECT *, ROW_NUMBER() OVER(PARTITION BY LegKey ORDER BY UpdateID DESC) AS RowNumber FROM Data.Crew) c
INNER JOIN
Data.CrewDetail cd
ON c.UpdateID = cd.CrewUpdateID
AND cd.IsPassive = 0
AND RowNumber = 1
INNER JOIN
Data.Leg l
ON c.LegKey = l.LegKey
)
SELECT
sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix AS Flight
, sac.DepartureDate
, sac.DepartureAirport
, sac.CREWBASE
, sac.CREWTYPE
, sac.EMPNO
, sac.FIRSTNAME
, sac.LASTNAME
, sac.SEX
FROM
Staging.SabreAssignedCrew sac
LEFT JOIN CTE cte
ON sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix = cte.Carrier + CAST(cte.FlightNumber AS VARCHAR) + cte.Suffix
AND sac.DepartureDate = cte.ScheduledDepartureDate
PLEASE TRY THIS.
SELECT Flight,
DepartureDate,
DepartureAirport,
CREWBASE,
SUM(CASE WHEN CREWTYPE = 'F' THEN 1 ELSE 0 END) AS CabinCrew ,
SUM(CASE WHEN CREWTYPE = 'C' THEN 1 ELSE 0 END) AS CockpitCrew
FROM #Table
GROUP BY Flight, DepartureDate, DepartureAirport, CREWBASE
Please Try This:
select Flight, DepartureDate, DepartureAirport,CREWBASE,
count(case when CREWTYPE='F' then 1 end ) as CabinCrew,count(case when CREWTYPE='C' then 1 end ) as CockpitCrew
from Staging.SabreAssignedCrew
group by Flight, DepartureDate, DepartureAirport,CREWBASE

Self join with inner and outer join query

I have a table that is set up so that one column (attribute) contains information like first name, last name, account number and any other information related to a thing in the database. Another column (attributeType) contains a number indicating what the attribute is e.g. 1 might be first name, 2 last name and 3 account number etc. There is another column (enddate) indicating if the record is current by having a date there. Usually it will be set to the year 9999 when current and some date in the past otherwise. All data describing the same thing has a unique value too in another column (entity) so that each record with the same number in the entity column will be describing the one person. E.g.
entity attribute attributetype enddate
------ --------- ------------- --------
1 ben 1 9999-1-1
1 alt 2 9999-1-1
1 12345 3 9999-1-1
2 sam 1 9999-1-1
2 smith 2 9999-1-1
2 98765 3 1981-1-1
I want to select a person from the above table with a specific 1st and last name where the name will be current but not output the account number if it is not. Assuming the table is called tblAccount I do the following for the name part:
select ta1.attribute '1st Name', ta2.attribute 'last name'
from tblAccount ta1
inner join tblAccount ta2 on ta1.entity = ta2.entity
where ta1.attribute = 'sam' and ta2.attribute = 'smith'
and ta1.attributetype = 1 and ta2. attributetype = 2
and ta1.enddate > getdate() and ta2.enddate > getdate()
and it outputs the first and last names as expected, but when I want to include the account number column I get nothing output:
select ta1.attribute '1st Name', ta2.attribute 'last name', ta3.attribute 'account#'
from tblAccount ta1
inner join tblAccount ta2 on ta1.entity = ta2.entity
left join tblAccount ta3 on ta1.entity = ta3.entity
where ta1.attribute = 'sam' and ta2.attribute = 'smith'
and ta1.attributetype = 1 and ta2. attributetype = 2
and ta1.enddate > getdate() and ta2.enddate > getdate()
and ta3.attributetype = 3 and ta3.enddate > getdate()
What I would like to see is the first and last names output with nothing in the account# column in the above case where it is not current. What am I doing wrong and how can I correct this query?
You have to move the date comparison to the join condition:
select ta1.attribute '1st Name'
, ta2.attribute 'last name'
, ta3.attribute 'account#'
from tblAccount ta1
inner join tblAccount ta2
on ta1.entity = ta2.entity
and ta1.attributetype = 1 and ta2. attributetype = 2
and ta1.enddate > getdate() and ta2.enddate > getdate()
left join tblAccount ta3 on ta1.entity = ta3.entity
and ta3.attributetype = 3 and ta3.enddate > getdate()
where ta1.attribute = 'sam' and ta2.attribute = 'smith'
When it's in the where clause it's comparing getdate() to NULL if there is no account, which returns NULL. So no record.
EDIT:
In response to the valid concern about multiple valid records, and to make the code a little more maintenance freindly:
DECLARE #FNAME VARCHAR(50) = 'sam'
, #LNAME VARCHAR(50) = 'smith'
, #now DATETIME2(7) = GETDATE();
SELECT
name.[1st Name]
, name.[last name]
, name.entity
,
(
select
top 1
ta3.attribute
FROM tblAccount ta3
WHERE
ta3.entity = name.entity
and
ta3.attributetype = 3
and
ta3.enddate > #now
ORDER BY
ta3.enddate
)
FROM
(
select
ta1.attribute '1st Name'
, ta2.attribute 'last name'
, ta.entity
, ROW_NUMBER()
OVER(
PARTITION BY
ta1.entity
ORDER BY
ta1.enddate
) r
from
tblAccount ta1
inner join tblAccount ta2
on
ta1.entity = ta2.entity
and
ta2. attributetype = 2
and
ta2.enddate > #now
and
ta2.attribute = #LNAME
where
ta1.attributetype = 1
and
ta1.attribute = #fname
and
ta1.enddate > #now
) name
WHERE
NAME.r = 1
;
This code works around the implied assumptions of one entity per first/last name and exactly one enddate after the execution time. The variables are a little more stored proc friendly, and allow you to change the "as of" date. And if you're stuck with EAV, you will likely want stored procs. I'm taking the first record ending after the date in question, on the assumption that any later record(s) should only be valid after that one expires. Maybe it's overkill, since it's beyond the scope of the OP's question but it's a valid point.
I say "stuck with EAV". While EAV isn't always bad; neither is shooting someone in the back. In either case, you'd better have solid justification if you expect to get it past a jury. In a NoSQL storage pattern it's fine, but EAV is usually a poor implementation pattern for the RDBMS paradigm.
Though from the OP's later comment, it looks like he's hit on one of the better reasons.
Each attribute is actually a distinct entity in this model, but they are all sharing the same storage in the same physical table (Why?). This yields:
with data as (
select entity = 1, attribute = 'ben', attributeType=1, enddate = convert(datetime,'99990101') union all
select entity = 1, attribute = 'alt', attributeType=2, enddate = convert(datetime,'99990101') union all
select entity = 1, attribute = '12345', attributeType=3, enddate = convert(datetime,'99990101') union all
select entity = 2, attribute = 'sam', attributeType=1, enddate = convert(datetime,'99990101') union all
select entity = 2, attribute = 'smith', attributeType=2, enddate = convert(datetime,'99990101') union all
select entity = 2, attribute = '67890', attributeType=3, enddate = convert(datetime,'99990101') union all
select entity = 2, attribute = '68790', attributeType=3, enddate = convert(datetime,'20130331') union all
select entity = 2, attribute = '876', attributeType=3, enddate = convert(datetime,'19810101')
)
select top 1
FirstName, LastName, AccountNum
from (
select top 1
a1.entity, FirstName, LastName
from (
select entity, enddate, attribute as FirstName
from data d
where d.enddate >= getdate()
and attributeType = 1
) a1
join (
select entity, enddate, attribute as LastName
from data
where enddate >= getdate()
and attributeType = 2
) a2 on a1.entity = a2.entity
and a1.enddate = a2.enddate
where FirstName = 'sam' and LastName = 'smith'
and a1.enddate >= getdate() and a2.enddate >= getdate()
order by a1.enddate
) E
left join (
select entity, enddate, attribute as AccountNum
from data
where enddate >= getdate()
and attributeType = 3
) a3 on a3.entity = E.entity
order by a3.enddate
returning:
FirstName LastName AccountNum
--------- -------- ----------
sam smith 68790
Note that it is quite common for accountign departments, at least, to enter future transactions during quiet times of the month, especially if those transactions will take effect during busy times of the month (ie month-end). The same for annual transactions. One should not assume that only one record can exist with an expiry > getdate().