I am trying to build a BQL query using the same table more than once. In my example below I am trying to use POVendorInventory as it relates to the default for the item and for each item warehouse (reason for the table listed twice in the query).
How do I do this in an Acumatica BQL Query. My current query is:
foreach (PXResult<INItemSite, InventoryItem, POVendorInventory, POVendorInventory> result in PXSelectJoin<INItemSite,
InnerJoin<InventoryItem, On<INItemSite.inventoryID, Equal<InventoryItem.inventoryID>>,
LeftJoin<POVendorInventory, On<InventoryItem.inventoryID, Equal<POVendorInventory.inventoryID>
, And<InventoryItem.preferredVendorID, Equal<POVendorInventory.vendorID>
, And<InventoryItem.preferredVendorLocationID, Equal<POVendorInventory.vendorLocationID>>>>,
LeftJoin<POVendorInventory, On<INItemSite.preferredVendorID, Equal<POVendorInventory.vendorID>,
And<INItemSite.inventoryID, Equal<POVendorInventory.inventoryID>>>>>>,
Where<InventoryItem.stkItem, Equal<boolTrue>>,
OrderBy<Asc<INItemSite.inventoryID, Asc<INItemSite.siteID>>>>.Select(graph))
{
var poVendorInventoryDefault = (POVendorInventory)result[2];
var poVendorInventorySite = (POVendorInventory)result[3];
}
The above results in the following error when the query is executed:
The correlation name 'POVendorInventory' is specified multiple times in a FROM clause.
The similar query in MS SQL is:
SELECT s.InventoryID ,
i.InventoryCD ,
s.SiteID ,
n.SiteCD ,
s.PreferredVendorID ,
s.PreferredVendorOverride ,
pd.VendorID ,
pd.AddLeadTimeDays ,
ps.VendorID ,
ps.AddLeadTimeDays
FROM dbo.INItemSite s
INNER JOIN dbo.InventoryItem i ON s.CompanyID = i.CompanyID
AND s.InventoryID = i.InventoryID
INNER JOIN dbo.INSite n ON s.CompanyID = n.CompanyID
AND s.SiteID = n.SiteID
LEFT JOIN dbo.POVendorInventory pd ON i.CompanyID = pd.CompanyID
AND i.InventoryID = pd.InventoryID
AND i.PreferredVendorID = pd.VendorID
AND i.PreferredVendorLocationID = pd.VendorLocationID
LEFT JOIN dbo.POVendorInventory ps ON s.CompanyID = ps.CompanyID
AND s.InventoryID = ps.InventoryID
AND s.PreferredVendorID = ps.VendorID
WHERE s.CompanyID = 2
AND i.StkItem = 1
ORDER BY s.InventoryID, s.SiteID
The following does not work either.
[Serializable]
public class POVendorInventoryTwo : POVendorInventory{}
PXResult<INItemSite, InventoryItem, POVendorInventoryTwo, POVendorInventory> result in PXSelectJoin<INItemSite,
InnerJoin<InventoryItem, On<INItemSite.inventoryID, Equal<InventoryItem.inventoryID>>,
LeftJoin<POVendorInventoryTwo, On<InventoryItem.inventoryID, Equal<POVendorInventoryTwo.inventoryID>
, And<InventoryItem.preferredVendorID, Equal<POVendorInventoryTwo.vendorID>
, And<InventoryItem.preferredVendorLocationID, Equal<POVendorInventoryTwo.vendorLocationID>>>>,
LeftJoin<POVendorInventory, On<INItemSite.preferredVendorID, Equal<POVendorInventory.vendorID>,
And<INItemSite.inventoryID, Equal<POVendorInventory.inventoryID>>>>>>,
Where<InventoryItem.stkItem, Equal<boolTrue>>,
OrderBy<Asc<INItemSite.inventoryID, Asc<INItemSite.siteID>>>>.Select(graph)
But as the answer mentions you need to use POVendorInventoryTwo for the second usage like so:
PXResult<INItemSite, InventoryItem, POVendorInventory, POVendorInventoryTwo> result in PXSelectJoin<INItemSite,
InnerJoin<InventoryItem, On<INItemSite.inventoryID, Equal<InventoryItem.inventoryID>>,
LeftJoin<POVendorInventory, On<InventoryItem.inventoryID, Equal<POVendorInventory.inventoryID>
, And<InventoryItem.preferredVendorID, Equal<POVendorInventory.vendorID>
, And<InventoryItem.preferredVendorLocationID, Equal<POVendorInventory.vendorLocationID>>>>,
LeftJoin<POVendorInventoryTwo, On<INItemSite.preferredVendorID, Equal<POVendorInventoryTwo.vendorID>,
And<INItemSite.inventoryID, Equal<POVendorInventoryTwo.inventoryID>>>>>>,
Where<InventoryItem.stkItem, Equal<boolTrue>>,
OrderBy<Asc<INItemSite.inventoryID, Asc<INItemSite.siteID>>>>.Select(graph)
What I've done in the past is subclass the DAC and query off that.
Something like this:
public class POVendorInventoryTwo : POVendorInventory
{}
Then in your BQL, use this subclassed version for the second value.
Related
SELECT partition_int, clustering_int, value_string
FROM test_ks1.test WHERE partition_int = ? AND clustering_int IN ?
Prepared select query with in clause throws the following exception:
java.lang.ClassCastException: class com.datastax.oss.driver.internal.core.type.PrimitiveType cannot be cast to class com.datastax.oss.driver.api.core.type.ListType
(com.datastax.oss.driver.internal.core.type.PrimitiveType and com.datastax.oss.driver.api.core.type.ListType are in unnamed module of loader 'app')
at com.datastax.oss.driver.internal.core.type.codec.registry.CachingCodecRegistry.inspectType(CachingCodecRegistry.java:343)
at com.datastax.oss.driver.internal.core.type.codec.registry.CachingCodecRegistry.codecFor(CachingCodecRegistry.java:256)
at com.datastax.oss.driver.internal.core.data.ValuesHelper.encodePreparedValues(ValuesHelper.java:112)
at com.datastax.oss.driver.internal.core.cql.DefaultPreparedStatement.bind(DefaultPreparedStatement.java:159)
Using datastax oss driver - version 4.5.1 and cosmosDB.
The query works with cassadra as docker and works in cqlsh with CosmosDB.
Queries used:
CREATE TABLE IF NOT EXISTS test_ks1.test (partition_int int, value_string text, clustering_int int, PRIMARY KEY ((partition_int),clustering_int))
Prepare the statement: INSERT INTO test_ks1.test (partition_int,clustering_int,value_string) values (?,?,?)
Insert values: 1,1,”a” | 1,2,”b”
Prepare the statement: SELECT partition_int, clustering_int, value_string FROM test_ks1.test WHERE partition_int = ? AND clustering_int IN ?
Execute with parameters 1,List.of(1,2)
The expected parameter is an integer and not list of integers
Sample code of the select prepared statement:
final CqlSessionBuilder sessionBuilder = CqlSession.builder()
.withConfigLoader(loadConfig(sessionConfig));
CqlSession session = sessionBuilder.build();
PreparedStatement statement = session.prepare(
"SELECT partition_int, clustering_int,"
+ "value_string FROM test_ks1.test WHERE partition_int = ? "
+ "AND clustering_int IN ?");
com.datastax.oss.driver.api.core.cql.ResultSet rs =
session.execute(statement.bind(1,List.of(1, 2)));
Is there a workaround to use prepared select queries with in clause?
Thanks.
My suggestion would be to use an work around like this:
//IDS you want to use;
List<Integer> list = Arrays.asList(1, 2);
// Multiply the number of question marks
String markers = StringUtils.repeat("?,", list.size()-1);
//Final query
final String query = "SELECT * FROM test_ks1.test where clustering_int in ("+markers+" ?)";
PreparedStatement prepared = session.prepare(query);
BoundStatement bound = prepared.bind(list.toArray()).setIdempotent(true);
List<Row> rows = session.execute(bound).all();
I have tried on my end and it works with me.
Now on your case you also have another parameter before the IN that you need to include in the parameter list but only after build the markers placeholder.
Good day
I am trying to convert my SQL to BQL but I don't know how to do the NOT IN Statment in BQL. I used NotIn2 with search I am not sure if that is right?
I keep on getting time out issues if I use it so I can't test
SELECT INTran.*,
FROM INTran
JOIN INTranSplit ON INTran.RefNbr = INTranSplit.RefNbr
JOIN InventoryItem ON InventoryItem.InventoryID = INTran.InventoryID
WHERE INTran.LotSerialNbr NOT IN
(
SELECT LotSerialNbr
FROM SOShipLineSplit
)
AND InventoryItem.inventoryCD = 'NIS004';
I am going to use it in a foreach loop with the below:
foreach (INTran item in PXSelectJoin<
INTran,
LeftJoin<INTranSplit,
On<INTranSplit.refNbr, Equal<INTran.refNbr>>,
LeftJoin<InventoryItem,
On< INTran.inventoryID, Equal<InventoryItem.inventoryID>>>>,
Where<INTran.lotSerialNbr, NotIn2<Search<SOShipLineSplit.lotSerialNbr>>,
And<InventoryItem.inventoryCD, Equal<Required<InventoryItem.inventoryCD>>>>
>.Select(Base, "NIS004")){}
Well, you cannot implement NotIn with subselect that easily in BQL. But here is what you can do:
You can alter the select to get the same result using join:
PXSelectJoin<INTran,
InnerJoin<INTranSplit, On<...>,
InnerJoin<InventoryItem, On<...>,
LeftJoin<SOShipLineSplit, On<SOShipLineSplit.lotSerialNbr, Equal<INTran.lotSerialNbr>>>>>,
Where<InventoryItem.inventoryCD, Equal<Required<InventoryItem.inventoryCD>>,
And<SOShipLineSplit.ShipmentNbr, IsNull>>
In that example you will only select lines for which SOShipLineSplit was not found
I have this autoquery implementation
var q = AutoQuery.CreateQuery(request, base.Request).SelectDistinct();
var results = Db.Select<ProductDto>(q);
return new QueryResponse<ProductDto>
{
Offset = q.Offset.GetValueOrDefault(0),
Total = (int)Db.Count(q),
Results = results
};
The request has some joins:
public class ProductSearchRequest : QueryDb<GardnerRecord, ProductDto>
, ILeftJoin<GardnerRecord, RecordToBicCode>, ILeftJoin<RecordToBicCode, GardnerBicCode>
{
}
The records gets returned correctly but the total is wrong. I can see 40,000 records in database but it tells me there is 90,000. There is multiple RecordToBicCode for each GardnerRecord so it's giving me the number of records multiplied by the number of RecordToBicCode.
How do I match the total to the number of GardnerRecord matching the query?
I am using PostgreSQL so need the count statement to be like
select count(distinct r.id) from gardner_record r etc...
Dores OrmLite have a way to do this?
I tried:
var q2 = q;
q2.SelectExpression = "select count(distinct \"gardner_record\".\"id\")";
q2.OrderByExpression = null;
var count = Db.Select<int>(q2);
But I get object reference not set error.
AutoQuery is returning the correct total count for your query of which has left joins so will naturally return more results then the original source table.
You can perform a Distinct count with:
Total = Db.Scalar<long>(q.Select(x => Sql.CountDistinct(x.Id));
This code results in timeout exception
String City_Code = null;
var result = (from r in myContext.TableA
where ( City_Code == r.City_Code )
select r ).ToList();
while this code will return quickly
String City_Code = null;
var result = (from r in myContext.TableA
where ( r.City_Code == City_Code )
select r ).ToList();
The difference is in the order of operands of the equality. The field City_Code of table TableA is of type nvarchar(20).
What is a possible reason for that???
update: The generated tsql for the 2 queries are identical except for that part: the first one has the condition " #p__linq__2 = [Extent1].[City_Code])" while the second has " [Extent1].[City_Code] = #p__linq__2)"
The value of #p_linq_2 when I notice the time difference is NULL. If I run the queries in ssms with NULL in place of #p_linq_2 they respond both very quickly
I'm trying to using the Subsonic Fluent query interface to create a simple inner join between two tables:
[SearchJobResults]
PK SearchJobResultId int
Name string
Desc string
[ParseResults]
PK ParseResultId int
Name string
SearchJobResultId int
There is a 1 to 1 relationship between these tables.
Keep in mind, I'm not using ActiveRecord. I have classes for ParseResult and SearchJobResult that work fine.
IDataProvider p = ProviderFactory.GetProvider("DemacDB");
SqlQuery query = new SqlQuery(p);
var q = new Select(p).From("ParseResults")
.InnerJoin<SearchJobResult>("SearchJobResultId","SearchJobResultId").GetRecordCount();
This code throws an exception:
Test method Models.SearchTests.TestSubsonicQueryMethods threw exception: System.InvalidOperationException: Don't know which column to join to - can't find column SearchJobResultId in table ParseResults.
I've looked at the source code for SubSonic to see where this execption is coming from:
private void CreateJoin<T>(string fromColumnName, string toColumnName, Join.JoinType type)
{
//see if we can find the table
var toTable = _provider.FindOrCreateTable(typeof(T));
//the assumption here is that the FromTable[0] is the table to join from
if(FromTables.Count == 0)
throw new InvalidOperationException("Can't join if there's no table to join to - make sure to use From() before InnerJoin");
if(toTable == null)
throw new InvalidOperationException("Can't find the table for this type. Try using the Column instead");
var fromColumn = FromTables[0].GetColumn(fromColumnName);
if(fromColumn == null)
throw new InvalidOperationException("Don't know which column to join to - can't find column " + fromColumnName + " in table " + FromTables[0].Name);
var toColumn = toTable.GetColumn(toColumnName);
if(toColumn == null)
throw new InvalidOperationException("Don't know which column to join to - can't find column " + toColumnName + " in table " + toTable.Name);
CreateJoin(fromColumn, toColumn, Join.JoinType.Inner);
}
I've tried using Aliases but that fails. Additionally, if I just do a simple query like this it works fine:
var d = new Select(p).From("ParseResults").GetRecordCount();
Turns out you need to use the Typed T overloads of From/Join to get this working.
var b = new Select(p).From<ParseResult>().InnerJoin<SearchJobResult>("SearchJobResultId", "SearchJobResultId").GetRecordCount();
Works as the FromTables collection in Subsonic now correctly gets enumerated because it's reading the type from the actual object and not the DB.