Say you have a stored procedure or function returning multiple rows, as discussed in How to return multiple rows from the stored procedure? (Oracle PL/SQL)
What would be a good way, using Scala, to "select * from table (all_emps);" (taken from URL above) and read the multiple rows of data that would be the result?
As far as I can see it is not possible to do this using Squeryl. Is there a scalaified tool like Squeryl that I can use, or do I have to drop to JDBC?
Functions that return tables are an Oracle specific feature, I doubt an ORM (be it Scala or even Java) would have support for such a proprietary extension.
So I think you're more or less on your own :).
Probably the easiest way is to use a plain JDBC java.sql.Statement and execute "select * from table (all_emps)" with the executeQuery method.
To address the second part of your question about a way to select from table in a more scala-esque way, I am using Slick. Quoting from their example documentation:
case class Coffee(name: String, supID: Int, price: Double)
implicit val getCoffeeResult = GetResult(r => Coffee(r.<<, r.<<, r.<<))
Database.forURL("...") withSession {
Seq(
Coffee("Colombian", 101, 7.99),
Coffee("Colombian_Decaf", 101, 8.99),
Coffee("French_Roast_Decaf", 49, 9.99)
).foreach(c => sqlu"""
insert into coffees values (${c.name}, ${c.supID}, ${c.price})
""").execute)
val sup = 101
val q = sql"select * from coffees where sup_id = $sup".as[Coffee]
// A bind variable to prevent SQL injection ^
q.foreach(println)
}
Though I am not sure how it's dealing (if at all) with stored procs/functions.
Related
If it's relevant I'm using Django with Django Rest Framework, django-mssql-backend and pyodbc
I am building some read only models of a legacy database using fairly complex queries and Django's MyModel.objects.raw() functionality. Initially I was executing the query as a Select query which was working well, however I received a request to try and do the same thing but with a table-valued function from within the database.
Executing this:
MyModel.objects.raw(select * from dbo.f_mytablefunction)
Gives the error: Invalid object name 'myapp_mymodel'.
Looking deeper into the local variables at time of error it looks like this SQL is generated:
'SELECT [myapp_mymodel].[Field1], '
'[myapp_mymodel].[Field2] FROM '
'[myapp_mymodel] WHERE '
'[myapp_mymodel].[Field1] = %s'
The model itself is mapped properly to the query as executing the equivalent:
MyModel.objects.raw(select * from dbo.mytable)
Returns data as expected, and dbo.f_mytablefunction is defined as:
CREATE FUNCTION dbo.f_mytablefunction
(
#param1 = NULL etc etc
)
RETURNS TABLE
AS
RETURN
(
SELECT
field1, field2 etc etc
FROM
dbo.mytable
)
If anyone has any explanation as to why these two modes of operation are treated substantially differently then I would be very pleased to find out.
Guess you've figured this out by now (see docs):
MyModel.objects.raw('select * from dbo.f_mytablefunction(%s)', [1])
If you'd like to map your table valued function to a model, this gist has a quite thorough approach, though no license is mentioned.
Once you've pointed your model 'objects' to the new TableFunctionManager and added the 'function_args' OrderedDict (see tests in gist), you can query it as follows:
MyModel.objects.all().table_function(param1=1)
For anyone wondering about use cases for table valued functions, try searching for 'your_db_vendor tvf'.
Using SQL Server Management
Using MVC VS 2013 for Web
Being in a Controller
Here materialnumb it's a LINQ query that always return only one value.
Being the following...
var materialnumb = (from r in db.MaterialNumber
where r.MaterialNumber == 80254842
select r.MaterialNumber);
I have another LINQ query from a SQL view that involves several other tables with inner join statements and so on (which includes the previous table db.MaterialNumber) that goes like this:
var query = (from r in db.SQLViewFinalTable
where r.MaterialNumber == Convert.ToInt32(materialnumb.MaterialNumber)
select r
I want to sort all the materials by the retrieved material number from the first query but it drops the following error when I try to pass the query as a model for my View:
LINQ to Entities does not recognize the method 'Int32
ToInt32(System.String)' method, and this method cannot be translated
into a store expression.
I assume this is because the query is an object even if its has just one value so it can't be converted into a single Int32.
Even more, the query it's not being executed, it's just a query...
So, how can achieve my goal?
Additional information: I tried to convert the query outside the "final" query. It still doesn't work.
Additional information: This is just an example, the true query actually has several more other querys embedded and this other querys have also other querys in them, so I need a practical way.
Additional information: I have also tried to convert the query into a string and then again into an int.
Try this:
var materialnumb = (from r in db.MaterialNumber
where r.MaterialNumber == 80254842
select r.MaterialNumber).FirstOrDefault();
var query = from r in db.SQLViewFinalTable
where r.MaterialNumber == materialnumb
select r
But I can not get whay are you filtering by 80254842 and selecting the same value? You can do directly:
var query = from r in db.SQLViewFinalTable
where r.MaterialNumber == 80254842
select r
I "inherited" a db with a field in a table where there are lowercase and uppercase mixed together, eg.
gateway 71, HOWARD BLVD, Chispa, NY
They aren't easily "splittable" with code because they don't always come in this form. What I need is a way to extract only uppercase letters. Is this possible with SQLite?
This is a case where it may just be easier (and perhaps quicker) to SELECT with any additional WHERE requirements you may have and create a cursor to iterate over the results doing your uppercase checks in code.
Another option with SQLite would be to create a custom function, so you could do something like:
SELECT foo WHERE MYISALLUPPERFUNC(foo) = 1;
As NuSkooler mentions, this is probably easier and faster to do using a cursor; an especially attractive option if you will only have to do this once.
Here's a quick example (using built-in SQLite from Python REPL):
import sqlite3
with sqlite3.connect(":memory:") as conn:
conn.execute('''create table t (c, newc);''')
conn.commit()
conn.execute('''insert into t (c) values (?);''', ('testing MAIN ST',))
conn.commit()
results = conn.execute('select c from t;').fetchall()
for line in results:
tokens = line[0].split()
filtered_tokens = [i for i in tokens if i.isupper()]
newc = ' '.join(filtered_tokens)
conn.execute('update t set newc = ?;',(newc,))
conn.commit()
conn.execute('''select c,newc from t;''').fetchone()
# (u'testing MAIN ST', u'MAIN ST')
I have a CLR UDT that would benefit greatly from table-valued methods, ala xml.nodes():
-- nodes() example, for reference:
declare #xml xml = '<id>1</id><id>2</id><id>5</id><id>10</id>'
select c.value('.','int') as id from #xml.nodes('/id') t (c)
I want something similar for my UDT:
-- would return tuples (1, 4), (1, 5), (1, 6)....(1, 20)
declare #udt dbo.FancyType = '1.4:20'
select * from #udt.AsTable() t (c)
Does anyone have any experience w/ this? Any help would be greatly appreciated. I've tried a few things and they've all failed. I've looked for documentation and examples and found none.
Yes, I know I could create table-valued UDFs that take my UDT as a parameter, but I was rather hoping to bundle everything inside a single type, OO-style.
EDIT
Russell Hart found the documentation states that table-valued methods are not supported, and fixed my syntax to produce the expected runtime error (see below).
In VS2010, after creating a new UDT, I added this at the end of the struct definition:
[SqlMethod(FillRowMethodName = "GetTable_FillRow", TableDefinition = "Id INT")]
public IEnumerable GetTable()
{
ArrayList resultCollection = new ArrayList();
resultCollection.Add(1);
resultCollection.Add(2);
resultCollection.Add(3);
return resultCollection;
}
public static void GetTable_FillRow(object tableResultObj, out SqlInt32 Id)
{
Id = (int)tableResultObj;
}
This builds and deploys successfully. But then in SSMS, we get a runtime error as expected (if not word-for-word):
-- needed to alias the column in the SELECT clause, rather than after the table alias.
declare #this dbo.tvm_example = ''
select t.[Id] as [ID] from #this.GetTable() as [t]
Msg 2715, Level 16, State 3, Line 2
Column, parameter, or variable #1: Cannot find data type dbo.tvm_example.
Parameter or variable '#this' has an invalid data type.
So, it seems it is not possible after all. And even if were possible, it probably wouldn't be wise, given the restrictions on altering CLR objects in SQL Server.
That said, if anyone knows a hack to get around this particular limitation, I'll raise a new bounty accordingly.
You have aliased the table but not the columns. Try,
declare #this dbo.tvm_example = ''
select t.[Id] as [ID] from #this.GetTable() as [t]
According to the documentation, http://msdn.microsoft.com/en-us/library/ms131069(v=SQL.100).aspx#Y4739, this should fail on another runtime error regarding incorrect type.
The SqlMethodAttribute class inherits from the SqlFunctionAttribute class, so SqlMethodAttribute inherits the FillRowMethodName and TableDefinition fields from SqlFunctionAttribute. This implies that it is possible to write a table-valued method, which is not the case. The method compiles and the assembly deploys, but an error about the IEnumerable return type is raised at runtime with the following message: "Method, property, or field '' in class '' in assembly '' has invalid return type."
They may be avoiding supporting such a method. If you alter the assembly with method updates this can cause problems to the data in UDT columns.
An appropriate solution is to have a minimal UDT, then a seperate class of methods to accompany it. This will ensure flexibility and fully featured methods.
xml nodes method will not change so it is not subject to the same implemetation limitations.
Hope this helps Peter and good luck.
I understand that in Postgres pure, you can pass an integer array into a function but that this isn't supported in the .NET data provider Npgsql.
I currently have a DbCommand into which I load a call to a stored proc, add in a parameter and execute scalar to get back an Id to populate an object with.
This now needs to take n integers as arguments. These are used to create child records linking the newly created record by it's id to the integer arguments.
Ideally I'd rather not have to make multiple ExecuteNonQuery calls on my DbCommand for each of the integers, so I'm about to build a csv string as a parameter that will be split on the database side.
I normally live in LINQ 2 SQL savouring the Db abstraction, working on this project with manual data access it's all just getting a bit dirty, how do people usually go about passing these kinds of parameters into postgres?
See: http://www.postgresql.org/docs/9.1/static/arrays.html
If your non-native driver still does not allow you to pass arrays, then you can:
pass a string representation of an array (which your stored procedure can then parse into an array -- see string_to_array)
CREATE FUNCTION my_method(TEXT) RETURNS VOID AS $$
DECLARE
ids INT[];
BEGIN
ids = string_to_array($1,',');
...
END $$ LANGUAGE plpgsql;
then
SELECT my_method(:1)
with :1 = '1,2,3,4'
rely on Postgres itself to cast from a string to an array
CREATE FUNCTION my_method(INT[]) RETURNS VOID AS $$
...
END $$ LANGUAGE plpgsql;
then
SELECT my_method('{1,2,3,4}')
choose not to use bind variables and issue an explicit command string with all parameters spelled out instead (make sure to validate or escape all parameters coming from outside to avoid SQL injection attacks.)
CREATE FUNCTION my_method(INT[]) RETURNS VOID AS $$
...
END $$ LANGUAGE plpgsql;
then
SELECT my_method(ARRAY [1,2,3,4])
I realize this is an old question, but it took me several hours to find a good solution and thought I'd pass on what I learned here and save someone else the trouble. Try, for example,
SELECT * FROM some_table WHERE id_column = ANY(#id_list)
where #id_list is bound to an int[] parameter by way of
command.Parameters.Add("#id_list", NpgsqlDbType.Array|NpgsqlDbType.Integer).Value = my_id_list;
where command is a NpgsqlCommand (using C# and Npgsql in Visual Studio).
You can always use a properly formatted string. The trick is the formatting.
command.Parameters.Add("#array_parameter", string.Format("{{{0}}}", string.Join(",", array));
Note that if your array is an array of strings, then you'll need to use array.Select(value => string.Format("\"{0}\", value)) or the equivalent. I use this style for an array of an enumerated type in PostgreSQL, because there's no automatic conversion from the array.
In my case, my enumerated type has some values like 'value1', 'value2', 'value3', and my C# enumeration has matching values. In my case, the final SQL query ends up looking something like (E'{"value1","value2"}'), and this works.
Full Coding Structure
postgresql function
CREATE OR REPLACE FUNCTION admin.usp_itemdisplayid_byitemhead_select(
item_head_list int[])
RETURNS TABLE(item_display_id integer)
LANGUAGE 'sql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
SELECT vii.item_display_id from admin.view_item_information as vii
where vii.item_head_id = ANY(item_head_list);
$BODY$;
Model
public class CampaignCreator
{
public int item_display_id { get; set; }
public List<int> pitem_head_id { get; set; }
}
.NET CORE function
DynamicParameters _parameter = new DynamicParameters();
_parameter.Add("#item_head_list",obj.pitem_head_id);
string sql = "select * from admin.usp_itemdisplayid_byitemhead_select(#item_head_list)";
response.data = await _connection.QueryAsync<CampaignCreator>(sql, _parameter);