Calling an SQL function from a Subsonic.Select - subsonic

I asked the following question on the subsonic forum, but only seemed to get one response, so I thought I'd post up here as well to see if anyone could shed some more light on the problem...
I wish to create the following SQL statement through SubSonic using the Select tool (or Query tool) .. it uses a custom function called "SPLIT()":
SELECT * FROM VwPropertyList
WHERE VwPropertyList.idCreatedBy = 123
AND VwPropertyList.idCounty = 45
AND 29 IN (SELECT Item FROM SPLIT(DistrictGroupList, ','))
(the last part of this SQL uses the SPLIT function)
My subsonic equivalent looks like the following...
Dim mySelect As New SubSonic.Select
mySelect.From(VwPropertyList.Schema)
mySelect.Where(VwPropertyList.Columns.IdCreatedBy).IsEqualTo(123)
mySelect.And(VwPropertyList.Columns.IdCounty).IsEqualTo(45)
mySelect.And(29).In(New SubSonic.Select("Item").From("SPLIT("
&
VwPropertyList.Columns.DistrictGroupList
& ", ',')"))
This doesn't work though due to the last part .. how can I add "AND 29 IN (SELECT Item FROM SPLIT(DistrictGroupList, ','))" into my Subsonic.Select ?
The response I got from the subsonic forum suggested I do away with Subsonic.Select and replace with hard-coded InlineQuery() statements .. like:
Dim SQL as String = "Select " &
VwPropertyList.Columns.Item SQL = SQL
& " From " &
VwPropertyList.Schema.TableName SQL =
SQL & " Where " &
VwPropertyList.Columns.IdCreatedBy & "
= #CreatedBy " SQL = SQL & " And " & VwPropertyList.Columns.IdCounty & " =
#County " SQL = SQL & " And
#DistrictGroup IN (Select Item From
SPLIT(DistrictGroupList,',')"
Items =
SubSonic.InlineQuery().ExecuteTypedList(Of
MyItem)(SQL, 123,45,29)
I would prefer to use SubSonic.Select if possible though so that I can avail of the paging functionality etc.
Any ideas?

You could do John's suggestion or you could write the SQL using our InlineQuery - which allows you to write raw SQL and pass in params:
var qry=new InlineQuery("SELECT * FROM table WHERE column=#param",value)

You could try to use the original query object (pre 2.1) like so (untested, from memory):
Query q = new Query(VwPropertyList.Schema.TableName);
q.WHERE("29 IN (SELECT Item FROM SPLIT(DistrictGroupList, ','))");
// pass q.ExecuteReader() to the Load() method of your view.

I would suggest that you use the original Query object as you are looking to get paging. Inline Query does not have any methods that allow paging.
If you absolutely wanted to use Subsonic.Select you could mesh the two ideas and run an Inline Query to get the list of values and then use a Regular Subsonic.Select and pass the retrieved values to the select case but then you would be making two trips to the db.
On a side note I prefer reading Subsonic.Select statements written using the fluent interface that it is namely
SubSonic.Select.AllColumnsFrom()
.Where(VwPropertyList.Columns.IdCreatedBy).IsEqualTo(123)
.And(VwPropertyList.Columns.IdCounty).IsEqualTo(45)
.ExecuteAsCollection();

thanks for the responses.
I ended up doing InlineQuery and just re-wrote the paging code that's normally produced by Subsonic.Select ... not the best solution but it seems to work.
It would be good if I could have done something like this though:
Dim s As New SubSonic.Select
s.From(VwPropertyList.Schema)
sWhere(VwPropertyList.Columns.IdCreatedBy).IsEqualTo(123)
sAnd(VwPropertyList.Columns.IdCounty).IsEqualTo(45)
s.And(29).In(New
InlineQuery("(SELECT Item FROM
SPLIT(DistrictGroupList, ','))"))

Related

Getting "Please rebuild this data combination" on a computer but not on another one

This is my first try at using the Power Query... I've build a "dynamic" query in which I can change the retrieved fields as well as the filtering fields and values to be used by the query.
It's working perfectly on my computer but as soon as I try to execute it on another computer, I get the "Please rebuild this data combination" error. I saw some post saying I'll have to kind of split my query but I have not been able to figure it out.
Here is what my 2 tables look like:
Condition and fields selection
and here is my Query with the error:
Query
This might not be very elegant, but it allow me, thru a VBA script, to generate the list of fields to be retrieved and to generate the condition to be used by the SQL.
Any idea why it's not working on the other computers or how to improved the solution I'm using?
Thank you!
Notes:
Hi, all my Privacy Level are already set to 'None'.
I've tried to parametrize my code but I can't figure how. The Where condition is dynamic: it could be Where Number = "1234" but in other condition, the where might be like: 'Where Assignee = "xyz"'.
Here is a simplified example of my code:
let
Source = Sql.Database("xxxx", "yyyy", [Query=
"Select network, testid
from CM3T1M1 "
& paramConditions[Conditions]{0} &
" "])
in
Source
rebuild query, Formula.Firewall
That's a feature to prevent prevent accidentally leaking data. You can change the privacy level to ignore it
See also: docs.microsoft/dataprivacyfirewall
Is the dynamic query inserting those cells into the SQL query ? Report Parameters are nice for letting the user change variables without having to re-edit the query.
Parameterized native SQL queries
from: https://blog.crossjoin.co.uk/2016/12/11/passing-parameters-to-sql-queries-with-value-nativequery-in-power-query-and-power-bi/
let
Source = Sql.Database("localhost", "Adventure Works DW"),
Test = Value.NativeQuery(
Source,
"SELECT * FROM DimDate
WHERE EnglishMonthName=#MonthName AND
EnglishDayNameOfWeek=#DayName",
[
MonthName = "March",
DayName = "Tuesday"
]
)
in
Test
Dynamic Power Query version of SQL Query
To dynamically generate this SQL Query
select NUMBER, REQUESTED_BY from SourceTable
where NUMBER = 404115
Table.SelectRows is your Where.
SelectColumns is your select
let
Source = ...,
filterByNum = 404115,
columnNames = {"NUMBER", "REQUESTED_BY"},
removedColumns = Table.SelectColumns(
Source, columnNames, MissingField.Error
),
// I used 'MissingField.Error' so you know right away
// if there's a typo or bug
// assuming you are comparing Source[NUMBER]
filteredTable = Table.SelectRows(
Source, each [NUMBER] = filterByNum
)
in
filteredTable

Query referencing another query

I can't execute a query in Power Query and the error that throws me is like:
Formula.Firewall: Query XXX references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
The code within this query is as below:
let
CallToFunction = myFunction,
#"Invoked Function" = CallToFunction(),
Source = Oracle.Database("myServer", [Query="SELECT * FROM myTable WHERE CustomerPK IN (" & #"Invoked Function" & ")"])
in
Source
myFunction is a function that uses a couple of other queries and eventually returns a string of primary keys that I can use to fill in the parenthesis of the WHERE clause of my SQL statement.
When I invoke the function alone it works correctly, so this must be an issue of how to call the function within the last query.
Any ideas?
You need to set the privacy settings of your data sources & workbook.
See https://support.office.com/en-ca/article/Privacy-levels-Power-Query-cc3ede4d-359e-4b28-bc72-9bee7900b540?ui=en-US&rs=en-CA&ad=CA

SQL Server CE and Datetime Select issue (C#)

I have a select that uses datetime, from two datetimepickers, in the WHERE clause. The SELECT runs fine, populates a datagrid, no problem, but bizzarely the datetime part of the SELECT is completely ignored and the whole thing returns a recordset as if only "WHERE x_account_id = " + subaccountID were employed:
SqlCeConnection conn = new SqlCeConnection(Lib.ConnectionString);
string sql = "SELECT x_scaleid, x_weight, x_timestamp FROM x WHERE x_account_id = " + subaccountID
+ " AND (x_timestamp BETWEEN #start_date AND #end_date) ORDER BY x_timestamp DESC";
SqlCeCommand cmd = new SqlCeCommand(sql, conn);
cmd.Parameters.Add("#start_date", SqlDbType.DateTime, 8).Value = dFromFilter.Value.Date;
cmd.Parameters.Add("#end_date", SqlDbType.DateTime, 8).Value = dToFilter.Value.Date;
SqlCeDataAdapter da = new SqlCeDataAdapter();
da.SelectCommand = cmd;
Not been able to find anyone with the same issue online, so I'm kind of stuck. Maybe I'm better off trying to convert all the datetimes to int's, and store them that way - always hated working with datetime types.
Before anyone asks, I've tried various versions of the clause, including the use of '<' and '>', as well as different CONVERT variations.
I 'solved' the issue, and by 'solved' I mean put in a hack.
I created a new column in the DB, type int, in the x table. As I populate x_timestamp with the current time, derived from the application, I populate this new column with a number constructed out of the date, in the format of 'yyyymmdd'. So when doing any filtering, using dates, I can simply do a numerical comparison using the two dates picked (again converted to similar int formats in the application). Works a treat.
It's not an ideal solution by any stretch, as it duplicates data in the DB, but deadlines are deadlines and if no one else can suggest a better one here, this one may be of help to anyone else with a similar problem in the future.

Subsonic:Selfjoin query need

I want to construct the query which is going to be used in .net. Below you can see the sql query, any one can give me the equivalent subsonic query
SELECT DISTINCT
a2.AccountID AS BID,
a2.AccountName AS Brand
FROM
Account a
INNER JOIN Account a2 ON a.ParentID = a2.AccountID
WHERE
a.AccountTypeID = 6
ORDER BY
Brand
Please help me.
SubSonic 2 or 3?
With SubSonic you always have a nice backdoor.
It's called InlineQuery in 2.x and CodingHorror in 3.x
e.g:
var result = DB.Query().ExecuteReader("SELECT DISTINCT
a2.AccountID AS BID,
a2.AccountName AS Brand
FROM Account a
INNER JOIN Account a2 ON a.ParentID = a2.AccountID
WHERE a.AccountTypeID = ?accounttypeid
ORDER BY Brand", 6);
If you want to stay with the fluent interface because of the syntax checking and the sql conversion. Here is another approach I could think of (SubSonic 2.2)
DataTable result = DB.Select(
"a1." + Account.Columns.AccountId + " as BID",
"a2." + Account.Columns.AccountName + " as Brand")
.From(Account.Schema.QualifiedName + " a1")
.InnerJoin(Account.Schema.QualifiedName + " a2",
"a2." + Account.Columns.account_id,
"a1", "a1." + Account.Columns.parent_id)
.Where("a1." + Account.Columns.AccountTypeId).IsEqualTo(6)
.OrderAsc("a2." + Account.Columns.AccountName)
.ExecuteDataSet().Tables[0];
But I never did this and I haven't verified it. But maybe it works.

linq to entity Contains() and nested queries

i've a trouble with linq, i'll explain on example :
i have a database table called Employee which got FirstName and LastName columns,
and a method to search employees which gets a nameList list as argument, the elements in this list are names formatted like this one "Fred Burn", or this1 "Grim Reaper",
already tryed these approaches with no luck =[
//just all employees
var allData = from emp in Context.Employee select emp;
var test1 = from emp in allData
where(emp.FirstName + " " + emp.LastName).Contains
("" + ((from n in nameList select n).FirstOrDefault()))
select emp;
var test2 = (from emp in allData
where (emp.FirstName + " " + emp.LastName)
== ((from n in nameList select n).FirstOrDefault())
select emp);
var test3 = from emp in allData
where (from n in nameList select n).Contains
(emp.FirstName + " " + emp.LastName)
select emp;
first and second queries give : {"Unable to create a constant value of type 'Closure type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."} exceptionand third : {"LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Collections.Generic.IEnumerable`1[System.String], System.String)' method, and this method cannot be translated into a store expression."}
would be glad to hear your suggestions :)
Thank You!
p.s.
yea i know it's possible to split names in list and compare them separately, but still curious why wont these queries work.
I assume nameList in this case is an in memory collection and that you are trying to use the LINQ to SQL trick creating a SQL "IN" clause inside of the Entity Framework. Unfortunately, EF doesn't support this syntax (yet). Depending on the number of records you are trying to match, you may be able to run separate queries for each child you are desiring. Alternatively, you could build an entitysql query using concatenation to append the multiple items from the nameList as separate OR clauses in the WHERE operation.

Resources