Using Access 2007
My table has 9 columns. I have 4 columns I need to use to select a value based on dates in 3 other columns. In a nutshell, I need the most current cost to show in the last column (Current_Cost). I have tried several embedded Iif statements to no avail. I don’t know if I have been looking at this too long and I’m just not seeing my error or if I’m way off base.
Columns in table:
Item Number
Original Cost
Original Date
Cost 1
Date 1
Cost 2
Date 2
Cost 3
Date 3
UPDATE MyTable
SET Current_Cost =
IIf([MyTable]![DATE3]>[MyTable]![DATE 2],[MyTable]![COST 3],
IIf([MyTable]![DATE2]>[MyTable]![DATE 1],[MyTable]![COST 2],
IIf([MyTable]![DATE1]>[MyTable]![ORIGINAL DATE],[MyTable]![COST 1],
[MyTable]![ORIGINAL COST])));
FYI - I inherited this table so please don't bash me for the way it is set up!
I think Switch is easier to manage than a bunch of nested IIf expressions.
First try a SELECT query to work out the Switch logic. I think this is close to what you're aiming for:
SELECT
Switch
(
[DATE 3]>[DATE 2], [COST 3],
[DATE 2]>[DATE 1], [COST 2],
[DATE 1]>[ORIGINAL DATE], [COST 1],
True, [ORIGINAL COST]
) AS test_expression,
*
FROM MyTable;
After you have the correct Switch expression, you can use that in your UPDATE.
UDATE MyTable
SET Current_Cost =
Switch
(
[DATE 3]>[DATE 2], [COST 3],
[DATE 2]>[DATE 1], [COST 2],
[DATE 1]>[ORIGINAL DATE], [COST 1],
True, [ORIGINAL COST]
)
Interesting question, because of the multiple dates. First off: can you guarantee that the following statement always holds true for your table:
[ORIGINAL DATE] <= [DATE1] <= [DATE2] <= [DATE3]
If it does, your query will be a simple switch statement as per #HansUp's answer.* If it doesn't, then things become a little more interesting. My approach would be (and note that this will only work within the same Access database file as the query) to define a VBA function that takes two values and returns their maximum, let's call it Max2, then use this function to find the latest date for each row in the table, then pick the cost corresponding to that date:
update MyTable
set Current_Cost = switch(
DATE3 = Max2(Max2(Max2([ORIGINAL DATE], DATE1), DATE2), DATE3), [COST 3]
, DATE2 = Max2(Max2(Max2([ORIGINAL DATE], DATE1), DATE2), DATE3), [COST 2]
, DATE1 = Max2(Max2(Max2([ORIGINAL DATE], DATE1), DATE2), DATE3), [COST 1]
, true, [ORIGINAL COST]
)
The Max2 VBA function (can be defined in any module):
public sub Max2(v1 as variant, v2 as variant) as variant
if v1 < v2 then
Max2 = v2
else
Max2 = v1
end if
end sub
By the way, why Max2 and not just Max4? Reusability. You can use a function like this in many different places.
* You can check with a simple SQL query. You can also enforce this date order as a table check constraint in Access. Let me know if you need more info.
Let's evaluate what an IIF does:
IIF(SOME_CHECK,true_condition,false_condition)
Looking at your code, we see:
If
[MyTable]![DATE3]>[MyTable]![DATE 2]
then set Current_cost to be:
[MyTable]![COST 3]
Else go on to the next check..
If
[MyTable]![DATE2]>[MyTable]![DATE 1]
then set Current_cost to be:
[MyTable]![COST 2]
Else go on to the next check..
If
[MyTable]![DATE1]>[MyTable]![ORIGINAL DATE]
then set Current_cost to be:
[MyTable]![COST 1]
Else set to
[MyTable]![ORIGINAL COST]
So, is that what you are looking for?
If it is not, you may need to reverse your logic.. Instead of Cost 3, Cost 2, Cost 1 then change to Cost 1, Cost 2, and Cost 3..
Related
i have a column in the report in which it stores calculated values depending on a set of iif statements, and calculate subtotals:
=sum(iif(Fields!EDLCode.Value = "X", Fields!Amount.Value, 0)/3 + iif(Fields!EDLCode.Value = XXX, Fields!SubjectAmt.Value, 0) - iif(InStr(Fields!Description1.Value, "YYY"),Fields!SubjectAmt.Value,0))
Question is how to show a grand total for that column in the report? Now it looks like that:
Figured it out. I had to set CDec(0) instead of just 0.
=sum(
iif(Fields!EDLCode.Value = "X", Fields!Amount.Value, CDec(0))/3 +
iif(Fields!EDLCode.Value = XXX, Fields!SubjectAmt.Value, CDec(0)) -
iif(InStr(Fields!Description1.Value, "YYY"),Fields!SubjectAmt.Value,CDec(0)))
This is working now.
There are a couple of problems with your expression
No quotes around XXX
InStr returns a value but you do not do anything with it
I have assume for the InStr function you are checking if "YYY" appears in the string, if not then modify the comparison to suit your needs..
Try this
=SUM(
IIF(Fields!EDLCode.Value = "X", Fields!Amount.Value, 0)/3 +
IIF(Fields!EDLCode.Value = "XXX", Fields!SubjectAmt.Value, 0) -
IIF(InStr(Fields!Description1.Value, "YYY") >0, Fields!SubjectAmt.Value, 0)
)
First off I know nothing about VB and the post I have seen on here refer to that, I am sure that this is a very simple thing to do so please help
I am trying to hve my TN Route be my primary key/no duplicates and have date driver 1 driver 2 and driver 3 all in diff cells and all side by side, and even though the tbl that it is pulling from the TN route is primary, it keeps adding additional rows for each driver.
See attached screenshot:
Thank you in advance.
Stan
data sheet view of query
This query will do it for you. Again, it's not preferable because in Access SQL tends to be a little messy on account of it not having features that more robust SQL platforms do - but it will work. You'll need to change the name of your Date column to Route Date in order for this to work, and replace my tblTest with whatever your table name is:
SELECT DISTINCT tblTest.[TN Route], tblTest.[Route Date], tA.[Driver 1], tB.[Driver 2], tC.[Driver 3]
FROM ((tblTest LEFT JOIN (SELECT tblTest.[TN Route], tblTest.[Route Date], [Driver 1] FROM tblTest WHERE [Driver 1] <> '') AS tA ON (tblTest.[Route Date] = tA.[Route Date]) AND (tblTest.[TN Route] = tA.[TN Route]))
LEFT JOIN (SELECT tblTest.[TN Route], tblTest.[Route Date], [Driver 2] FROM tblTest WHERE [Driver 2] <> '') AS tB ON (tblTest.[Route Date] = tB.[Route Date]) AND (tblTest.[TN Route] = tB.[TN Route]))
LEFT JOIN (SELECT tblTest.[TN Route], tblTest.[Route Date], [Driver 3] FROM tblTest WHERE [Driver 3] <> '') AS tC ON (tblTest.[Route Date] = tC.[Route Date]) AND (tblTest.[TN Route] = tC.[TN Route])
In Access 2010, go Create > Query Design > add your table, and then paste the SQL into the SQL view of the query designer. You can even make a standalone table out of the result.
New to SSRS 2012 & struggling.
I have a report - containing a subreport - on client data. When testing with one client (just to make sure everything was OK) it works perfectly.
When the filter's removed, it's timing out (it's actually saying it's been cancelled by the user, which it hasn't).
Obviously the inclusion of the subreport is the problem (as the main report runs fine without it).
My subreport can validly return multiple records per client. The subreport is grouped on ClientId. I then have a calculated field - say HasIP - that concatenates two fields (IC and PC ) to produce either YesYes or YesNo. The tablix is sorted by HasIP by Z to A.
The info in the ClientID footer are what I'm displaying.
ClientID HasIP
22 YesNo - has two records, but since it has a YesYes, I don't want this one
22 YesYes - has two records, but I want the this one
52 YesYes - may only have 1 record, I want this record
76 YesNo - may only have 1 record, I want this record
Theoretically a client can't have more than one instance of HasIP=YesYes & shouldn't have more than 2 records. How can I recreate this effect in Query Designer? Essentially if HasIP=yesyes, use that record, otherwise use the other record
If I can do this, I can then drop the subreport completely, add this dataset to my main report & use Lookup to get the data.
However, the way our report scenario is set up, I'm not permitted to change the query [I have to click Query Designer button in Dataset Properties] & I have no experience in MDX.
SOLVED!!!:
OK - here's what I've come up with.
Assign numeric order to IC and PC values
I concatenated the IC & PC field values together and assigned values and added the ID of the records in the original subreport. I called this field HasIP
=Switch(Fields!IC.Value+Fields!PC.Value="YesYes", 1,
Fields!IC.Value+Fields!PC.Value="YesNo", 2,
Fields!IC.Value+Fields!PC.Value="NoNo", 3) & "-" & Fields!R_Name.Value
This left me with 2-xxxx, 1-yyyy etc.
I then added a filter to my second dataset:
=Left(Fields!HasIP.Value, 1)
to exclude values of "NoNo"
Concatenate HasIP and other fields in Dataset2 (to be used by LookupSet)
In addition also had to convert the text values into code for output (eg Yes = 1, No = 2, Unknown = 3 etc). I did this by creating a calculated field in Dataset2 (in the report, not the query) which included the HasIP. I delimited HasIP from the value by using a dollar sign.
=Fields!HasIP.Value & "$" &
SWITCH(
left(Fields!CoR.Value, 1)="C", 1,
Left(Fields!CoR.Value, 1)="N", 2,
True, ""
)
This left me with 2-xxxx$2, 1-yyyy$1 etc.
Sort the LookupSet results
LookupSet creates an array (and yes, now you know too). I needed to sort this so that the one I'm after is the first value returned. This is achieved by copying and pasting the following into the custom code section of your report. (I've added the code to allow you to sort in reverse if you need it).
Function JoinSorted(m_Array As Object()) As String()
System.Array.Sort(m_Array)
' Array.Reverse(m_Array) 'uncomment this line if you want to sort in reverse
Dim k As Integer = 0
For i As Integer = 0 To m_Array.Length - 1
If i > 0 AndAlso m_Array(i).Equals(m_Array(i - 1)) Then
Continue For
End If
m_Array(k) = m_Array(i)
k += 1
Next
Dim fred As [String]() = New [String](k - 1) {}
System.Array.Copy(m_Array, 0, fred, 0, k)
Return fred
End Function
You call this by using the following in your report expression:
Join(
Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!YourField.Value,"Dataset2")
),""
)
So, regardless of how LookupSet wanted to return the array, I always got 1-yyyy$1 first.
Handling LookupSet output on the report - include default for no records
For some LookupSet results in the report, I needed return a default value if there were no records returned. Otherwise I needed to return the assigned value (1, 2, 3 etc). If found two ways to do this.
This checks to see if the array count [yes, by using length] is greater than zero. If so, then using a mid function on the array result to return the 14th character:
=SWITCH(
LookupSet(
Fields!Main_ID.Value, Fields!Main_ID.Value, Fields!Record_Name.Value, "Dataset2"
)
.Length=0,
2,
LookupSet(
Fields!Main_ID.Value, Fields!Main_ID.Value, Fields!Record_Name.Value, "Dataset2")
.Length>0,
1)
OR
This is the same:
=iif(
LookupSet(
Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Main_ID.Value,"Dataset2"
).Length>0,
Mid(
Split(
Join(
Code.JoinSorted(
LookupSet(
Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Main_ID.Value,"Dataset2")
)
,";")
,";").GetValue(0)
, 'start point of mid
InStr(
Join(
Code.JoinSorted(
LookupSet(
Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Main_ID.Value,"Dataset2"
)
)
,";")
,"$")
+1,
1),
"2"
)
Handling LookupSet output on the report - using of MID when length of value varies
In some cases the value I needed to return varied in length, eg 2 or 10. I also needed to return nothing if the LookupSet didn't return any results. I couldn't use "normal" versions of MID like this:
Mid(
Join(Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12d.Value,"Dataset2")),
";"),
InStr(
Join(
Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12d.Value,"Dataset2")
),
";"),
"$")+1,
(
InStr(
Join(
Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12d.Value,"Dataset2")
),
";"),
";")
-
InStr(
Join(
Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12d.Value,"Dataset2")
),
";"),
"$")
- 1)
)
as it threw #ERROR due to the use of -1 (at the end) making the string a negative length for some records.
So, here is what I could use:
=
Mid(
Split(
Join(
Code.JoinSorted(
LookupSet(Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12b.Value,"Dataset2")
),
";"),
";").GetValue(0)
,
InStr(
Join(
Code.JoinSorted(
LookupSet(
Fields!Main_ID.Value,Fields!Main_ID.Value,Fields!Q12b.Value,"Dataset2")
),
";"),
"$")
+1,
1)
By doing this, I could get the results I was after in the details & the footer.
I hope this can help someone else.
So basically my code involves a created a table which has the LAST COLUMN as the SUM of the previous two columns, with the first of the two coming from table X and the second of the two columns coming from the 'INNER JOIN OF table X with table Y'.
HOWEVER, I want to group ALL THREE of these columns by the 'COUNTERPARTY', a variable which is present BOTH in 'table X' AND in 'INNER JOIN OF TABLE X WITH TABLE Y.'
The tricky part is that there will be some COUNTERPARTIES for which we have data set 1 (coming from TABLE X) and some COUNTERPARTIES for which we have data set 2 (coming from INNER JOIN OF table X with table Y) and SOME FOR WHICH WE HAVE BOTH DATASETS! I WANT TO INCLUDE THE INTERSECTION AS WELL AS THE OUTLIERS BUT ONLY AFTER CHECKED AGAINST A MASTER KEY OF COUNTERPARTIES called c.COUNTERPTY.
Please carefully go through the code below to see how the above explanation is relevant to the problem at hand. I apologize for the length of the code.
select
p.Name as ENTITY, t.[Counterparty Code], c.CNTRPTY_DS as COUNTERPARTY, cs.Tier,
... irrelevant code removed
sum((t.[Current value decimal] - t.[Trade price decimal])/100 * case when t.[Buy Sell Code] = 'B'
then 1 else -1 end * t.[Open Amount]) as [OPEN MTM ($)],
sum((t2.[Weighted Average Settled Pair Off Price] - t2.[Trade price decimal])/100 * case when t2.[Buy Sell Code] = 'B'
then 1 else -1 end * ISNULL(PO.[Pairoff Amount],0)) as [Unsettled Pairoffs/ AOTs ($)],
sum((t.[Current value decimal] - t.[Trade price decimal])/100 * case when t.[Buy Sell Code] = 'B'
then 1 else -1 end * t.[Open Amount]) + sum((t2.[Weighted Average Settled Pair Off Price] - t2.[Trade price decimal])/100 * case when t2.[Buy Sell Code] = 'B'
then 1 else -1 end * ISNULL(PO.[Pairoff Amount],0)) as [TOTAL MTM Exposure ($)]
from
[la-w08-qrm-db-1].qrmprod.dbo.vw_QRM_Trades t2
inner join
[la-w08-qrm-db-1].qrmprod.dbo.VW_QRM_TRADE_PAIROFFS PO
ON
PO.[In Ticket Number] = t2.[Ticket number]
and PO.[Portfolio ID] = t2.[Portfolio ID]
and t2.[derivative type] = 'F' -- note repeat below
and t2.[forward type] ='MBS'
and t2.[Counterparty Code] not in ('PLS', 'PNCO')
and t2.[Portfolio ID] in (1,7)
and t2.[Settlement date] > GETDATE(),
prod.dbo.vw_QRM_Trades t,
prod.dbo.portdesc p,
prod.dbo.cptyall c,
prod.dbo.VW_MB_ACTIVE_RUN r,
pulsar.dbo.CntrPrtySetup CS,
pulsar.dbo.CntrPrtyTiers CT
where
r.mrktid = 1
And r.asmpid = 1
And r.cyclid = 1
and r.compid = t.[Company ID]
and r.portid = t.[Portfolio ID]
and p.PORTID = t.[Portfolio ID]
and c.COUNTERPTY = t.[Counterparty Code] --key piece of code
and cs.CNTRPTY_NO = c.CNTRPTY_NO
and cs.PortID = t.[Portfolio ID]
and cs.Tier = ct.Tier
and t.[derivative type] = 'F' -- note repeat above
and t.[forward type] ='MBS'
and t.[Counterparty Code] not in ('PLS', 'PNCO')
and t.[Portfolio ID] in (1,7)
and t.[Open Amount] > 0
group by
p.Name, c.CNTRPTY_DS , t.[Counterparty Code], cs.Tier -- yes this
order by
p.Name, c.CNTRPTY_DS , t.[Counterparty Code], cs.Tier -- and this
The way to do is was to actually use UNION in order to join three tables together in the order and given the properties I wanted from each of them. Eventually I did manage to finish the whole stored procedure!
I just added a couple of calculated columns to a stored procedure that returns a result set. I call it from C#/ .NET. The new columns (to on the end) are both returning a value of 0. Here's the first row of what I get back, and the sproc below it:
Daily Pricing and Volume 5/4/2012 5229 5249 5256 0 0
ALTER PROCEDURE [dbo].[spProcedureStatsCollectionCountComparisons]
AS
DECLARE #MaxDataDownloadDate date
SET #MaxDataDownloadDate = dbo.MostRecentTradeDateForDataDownload()
SELECT ProcedureName, TradeDate, LatestCount, PriorCount, AvgAllCounts,
((LatestCount-PriorCount)/PriorCount) AS PctChgLatestVsPrior,
((LatestCount-AvgAllCounts)/AvgAllCounts) AS PctChgLatestVsAvg
FROM vwProcedureStatsCollectionCountComparisons
WHERE TradeDate = #MaxDataDownloadDate
My question is, can I not use column alias' in a result set from a stored procedure, or is there some other issue at work that I'm missing? Thanks in advance..
As requested, the relevant C# code:
SqlDataReader collectionCounts = dal.ProcedureStatsCollectionCountComparisons();
int rowCounter = 4;
while (collectionCounts.Read())
{
wkhst.Cells[rowCounter, 1] = collectionCounts["ProcedureName"];
wkhst.Cells[rowCounter, 2] = collectionCounts["TradeDate"];
wkhst.Cells[rowCounter, 3] = collectionCounts["LatestCount"];
wkhst.Cells[rowCounter, 4] = collectionCounts["PriorCount"];
wkhst.Cells[rowCounter, 5] = collectionCounts["AvgAllCounts"];
wkhst.Cells[rowCounter, 6] = collectionCounts["PctChgLatestVsPrior"];
wkhst.Cells[rowCounter, 7] = collectionCounts["PctChgLatestVsAvg"];
rowCounter++;
}
excelApp.Visible = true;
As per my knowledge and based on the data provided, it is working as expected. This is because, you doing something like below.
SELECT ((5229 - 5249)/5249)
which always returns "0" as the first number is less than the second one.
EDIT:
SELECT (CAST((5229 - 5249) AS FLOAT)/ CAST(5249 AS FLOAT))