I'm trying to make a date range in a view work relative to today. But I'm not find any function to set in the query range to make it dynamic.
Example:
Creates:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW [dbo].[MYCUSTINVOICETABLEVIEW] AS
SELECT T1.INVOICEID AS INVOICEID,T1.DATAAREAID AS DATAAREAID,T1.PARTITION AS PARTITION,T1.RECID AS RECID
FROM CUSTINVOICETABLE T1
WHERE (INVOICEDATE<={ts '2017-07-18 00:00:00.000'})
GO
But instead of looking relative to last synchronization date, I want to look compared to today.
SELECT ... FROM CUSTINVOICETABLE T1
WHERE (INVOICEDATE<=GETDATE())
Any ideas how I can setup the query ranges for this?
Tried so far:
..GetDate()
..today()
..currentDate()
lessThanDate(0)
"< GETDATE()"
< currentSessionDateTime()
According to How to refresh/Synch View based on a Query with dynamic range?, it's not possible (for UserID()). I want to double check if that's the same case for dates. The view is being consumed by a other application on the same box (not an Ax form).
This isn't pretty and I still imagine there might be a better way, but here is a solution that I just tested. Obviously there are much better ways of doing this in x++, forms, and reports, but the result of the below can be queried externally from AX and will still return dynamic results.
You have a Query > View > Query > View structure, with the top level view being your consumable view.
The first view has the data you need and a computed date column, populated by the following code to get the dynamic date:
public server static str today()
{
return 'CONVERT (date, GETDATE())';
}
You then make a query of that view, and put an extended query range on it to check your field vs the dynamic GETDATE() column. You then have a view built on top of that query that your external application can consume.
In the example below, all field lists are set to dynamic yes. Obviously you would carry the relevant data from the root query all the way up.
The example in the picture results in the following view definitions:
CREATE VIEW "DBO".TESTVIEW AS SELECT T1.SALESID AS SALESID,
T1.RECEIPTDATEREQUESTED AS RECEIPTDATEREQUESTED,
T1.DATAAREAID AS DATAAREAID,T1.PARTITION AS PARTITION,T1.RECID AS RECID,
(CAST ((CONVERT (date, GETDATE())) AS DATETIME)) AS CURRENTDATE
FROM SALESTABLE T1
CREATE VIEW "DBO".TESTCONSUMABLEVIEW AS
SELECT T1.CURRENTDATE AS CURRENTDATE,T1.RECEIPTDATEREQUESTED AS RECEIPTDATEREQUESTED,
T1.SALESID AS SALESID,T1.DATAAREAID AS DATAAREAID,T1.PARTITION AS PARTITION,
T1.RECID AS RECID
FROM TESTVIEW T1 WHERE (RECEIPTDATEREQUESTED<CURRENTDATE)
My answer is based off #Spencer Kershaw's answer. So credit for his work, but I want to provide a more succinct answer that doesn't require a query and hopefully is clearer for others trying to accomplish the task.
To accomplish what you want, you need to do 3 things.
Create static method to use for computed column
Add a computed column to your view
Correctly put in the range by using some random field
1. Add this method to your view:
public server static str today()
{
return 'CONVERT (date, GETDATE())';
}
2. Right click on the fields node and click New>Date Computed Column. On the properties set ViewMethod = today.
3. Add a range. Choose dataAreaId for the field (this is arbitrary). Set the Value property equal to ("YourComparisonField" < "today"). The syntax can be important here.
This produces:
CREATE VIEW [dbo].[AAATESTVIEW]
AS
SELECT T1.ADDRESS AS ADDRESS
,T1.MODIFIEDDATETIME AS MODIFIEDDATETIME1
,T1.RECID AS RECID1
,T1.PARTITION AS PARTITION
,T1.RECID AS RECID
,(CAST((CONVERT(DATE, GETDATE())) AS DATETIME)) AS TODAY
FROM LOGISTICSPOSTALADDRESS T1
WHERE (N'modifiedDateTime1' < N'today')
GO
Related
I first created a SQL query and now I'm converting it into an AOT query in AX 2012 R3. I have everything else working except for one thing. I have a join in my SQL that is: JOIN dbo.INVENTJOURNALTABLE AS INV3 ON INV.INVENTBATCHID LIKE left(INV3.DESCRIPTION,17). In SQL this works and returns the data that I need.
I don't know how to create this join in the AOT query though.
That INV3.DESCRIPTION is a string that contains the InventBatchID.
Is there a way to do this kind of join?
In order to accomplish what you want with a Query object, it's difficult/unusual, and AX isn't designed to do this in a straight forward way and requires a very creative solution.
I would generally push towards writing a pure x++ query as I don't believe LEFT and LIKE can be natively combined, especially in a query. You can use * in the value for "like" as an option.
You may be able to accomplish using expressions in query ranges somehow.
If you must have a query, a way I can think is by combining a View, Computed Column, and a Query...and I can't guarantee it will work, but I can give you enough to have something to test with. Some of the information in this answer is pretty concentrated so look closely at everything to understand it.
Create a View, add the below computed column, then add it to a Query as pictured below. For the computed column, you need to add a new String field to the view and set the ViewMethod property to the name of the method. See here for more info about adding Computed Columns.
The Computed Column accomplishes the left(..., 17) part and you can browse the view to confirm.
The last part is trying to join either by a relation (pictured below, but it does not accomplish the like) or setting the Value property using an expression by following the link above. You may need to create a custom expression in \Classes\SysQueryRangeUtil. You have some experimenting to do to see if it works.
private static server str compColDescLeft()
{
#define.ViewName(InventJournalTableView)
#define.DataSourceName("InventJournalTable_1")
#define.FieldDescription("Description")
#define.LeftCount("17")
str sReturn;
str sLeftDesc;
DictView dictView;
dictView = new DictView(tableNum(#ViewName));
sLeftDesc = dictView.computedColumnString(#DataSourceName, #FieldDescription, FieldNameGenerationMode::FieldList, true);
sReturn = "left(" + sLeftDesc + ", " + #LeftCount + ")";
return sReturn;
}
I have table like
(1st photo)
table
What I should do to take this value to while select in x++?
(2c photo)
value
The short answer is you would need to take the return from the lookup, find the value in the table via the returned value (key), and take the Name field.
So this would be the data in your case for the first result:
InventLocation::find('11').Name
This is what's called a lookup. When you do a lookup, there are multiple methods that AX will determine what values to display. The one you're looking at is a lookup based upon the Extended Data Type relation.
EDT - In this case \Data Dictionary\Extended Data Types\InventLocationId
Table - which has a reference table of \Data Dictionary\Tables\InventLocation
Primary Key - which has an alternate primary key of \Data Dictionary\Tables\InventLocation\Indexes\InventLocationIdx, which I believe in this case determines the return value
AutoLookup - and the AutoLookup located at \Data Dictionary\Tables\InventLocation\Field Groups\AutoLookup determines which fields are displayed to the user as information.
If you want a custom lookup to return the InventLocation.Name field, you should look at the different methods available to you. This blog post is an excellent start to see different methods: https://kashperuk.blogspot.com/2009/04/lookup-methods-tutorial-custom-list.html
I have to build a specialized form which queries the InventTrans table for some purchase transactions.
The transactions must be selected, either with a non-empty Voucher, either with a non-empty Packing slip Id (PackingSlipId).
While looking how to specify this in a query range, I found that it was possible to associate this query range to the RecId of the table. Is this the usual and classic way to do this ? See my example (which seem to work).
QueryBuildDataSource qbds;
;
qbds = this.query().dataSourceTable(tableNum(inventTrans));
sysQuery::findOrCreateRange(qbds, fieldNum(InventTrans, RecId)).value(
strfmt('(%1 != "") || (%2 != "")',
fieldstr(InventTrans, Voucher),
fieldstr(InventTrans, PackingSlipId)));
Those are called range expressions and is the only way to state more complex queries with a Query object - see this MSDN page
In addition have a look at this Axaptapedia page (thanks to FH-Inway)
Regarding if it is the classical way: No - only use it if necessary
Im working in AX 2012.
I try to make code where i count all sales for each month and insert them into fields in a table.
These fields are called Sales1, Sales2, Sales3 etc... representing the months in a year.
is there a way i can select these fields and insert into them in a while select like this example below?
while select myTable where myTable.date >= startDate && myTable.date <= endDate
{
MyTable.("Sales" +MthOfYear(MyTable.Date)) += MyTable.SalesQty;
}
myTable.insert();
it's a stupid example, but it should show what i want to achieve... any ideas?
Regards
Kent
I think your main question is how to access a field by having its name in a string variable?
If that's the case then please see the following two links:
How to convert field name to its ID
How to access a table field by ID
In short: First of all you have to convert your field name to the corresponding field ID by using fieldName2Id. After that, you can access this field by using the syntax myTable.(fieldId).
To put it all together for your case:
myTable.(fieldName2Id(myTable.TableId, strfmt("%1%2", "Sales", mthofyr(myTable.Date)))) += myTable.SalesQty
If you have any problems or questions don't hesitate to ask via a comment.
While the fieldName2Id may save your day, it is an AX anti-pattern to have fields named Sales1, Sales2 ... Sales17. Why? Because AX supports arrays in tables (albeit only of a fixed size).
To use that, define a new extended data type SalesAmountMonth exending SalesAmount (or whatever).
Label the it "January". Then in the node "Array Elements" add an new array element for "February", "Marts" up till "December". See How to Define an Extended Data Type as an Array.
Then add the extended data type to your table.
Your field access is then quite simple:
myTable.Sales[mthofyr(myTable.Date)] += myTable.SalesQty;
I prefer using the intvNo function for date indexing like this, as it has more flexibility:
myTable.Sales[intvNo(myTable.date, startDate, IntvScale::YearMonth) + 1] += myTable.SalesQty;
By changing the IntvScale enumeration you can group by month, week, quarter or whatever it supports.
I am trying to correct the sort order of my ASP.NET drop down list.
The problem I have is that I need to select a distinct Serial number and have these numbers organised by DateTime Desc.
However I cannot ORDER BY DateTime if using DISTINCT without selecting the DateTime field in my query.
However if I select DateTime this selects every data value associated with a single Serial number and results in duplications.
The purpose of my page is to display data for ALL Serials, or data associated to one serial. When a new cycle begins (because it is a new production run) the Serial reverts to 1. So I cannot simply organise by serial number either.
When I use the following SQL statement the list box is in the order I require but after a period of time (usually a few hours) the order changes and appears to have no organised structure.
alt text http://img7.imageshack.us/i/captureky.jpg/
I'm fairly new to ASP.NET / SQL, does anyone know of a solution to my problem.
If you have multiple date times for each serial number, then which do you want to use for ordering? If the most recent, try this:
SELECT SerialNumber,
MAX(DateTimeField)
FROM Table
GROUP BY SerialNumber
ORDER BY 2 DESC
I don´t know if everybody agrees with that, but when I see a DISTINCT in a query the first thought that goes trough my mind is "This is wrong". Generally, DISTINCT is not necessary and it´s used when the person writing the query doesnt know very well what he is doing and this might be the case since you said you are new with Sql.
Without complete knowledge of your model is difficult to assist you a hundred percente, but I would say that you should use a GROUP BY clause instead of DISTINCT, then you can order it correctly.