nested SQL Statements with Propel? - sql

I'm trying to translate a SQL Statement into Propel, without so much success. I have this SQL Statement:
SELECT id, param1, param2
FROM Field1
WHERE id
in
(
SELECT DISTINCT Field1_id
FROM Field2
WHERE id in
(
SELECT DISTINCT `Field2_id`
FROM `Field3`
WHERE
`param7` is null
AND param5 > 40
)
) LIMIT 0, 1000
i started doing it in a raw Way:
$connection = Propel::getConnection();
$query = "my Query";
$statement = $connection->prepare($query);
$statement->execute();
$results = $statement->fetch(PDO::FETCH_ASSOC);
This works pretty well, but i can't do any Propel Actions on $results cause it is an Array.
So how can i translate this SQL into Propel without the raw Way?

A good quick-fix for this is to create a view in your database, and set up a read-only table in Propel for that view. You can then use your view model just as you would an ordinary Propel table. Now of course this is cheating, and is frowned upon by ORM purists, but it will get you going in the short term.
My approach is to try to refactor back to tables where I've used this for a trivial query, but for big, central queries (in particular complex queries that are used for primary drill-down screens) I've been more than happy to keep the view approach permanently.

As far as I know, Propel does not handle nested queries. Instead, you can write table subqueries.

Related

Create SQLite view as a union with source table name field [duplicate]

I want to write a query that examines all the tables in an SQLite database for a piece of information in order to simplify my post-incident diagnostics (performance doesn't matter).
I was hoping to write a query that uses the sqlite_master table to get a list of tables and then query them, all in one query:
SELECT Name
FROM sqlite_master
WHERE Type = 'table' AND (
SELECT count(*)
FROM Name
WHERE conditions
) > 0;
However when attempting to execute this style of query, I receive an error no such table: Name. Is there an alternate syntax that allows this, or is it simply not supported?
SQLite is designed as an embedded database, i.e., to be used together with a 'real' programming language.
To be able to use such dynamic constructs, you must go outside of SQLite itself:
cursor.execute("SELECT name FROM sqlite_master")
rows = cursor.fetchall()
for row in rows:
sql = "SELECT ... FROM {} WHERE ...".format(row[0])
cursor.execute(sql)

Is it possible to use a returned column value as a table name in an SQLite query?

I want to write a query that examines all the tables in an SQLite database for a piece of information in order to simplify my post-incident diagnostics (performance doesn't matter).
I was hoping to write a query that uses the sqlite_master table to get a list of tables and then query them, all in one query:
SELECT Name
FROM sqlite_master
WHERE Type = 'table' AND (
SELECT count(*)
FROM Name
WHERE conditions
) > 0;
However when attempting to execute this style of query, I receive an error no such table: Name. Is there an alternate syntax that allows this, or is it simply not supported?
SQLite is designed as an embedded database, i.e., to be used together with a 'real' programming language.
To be able to use such dynamic constructs, you must go outside of SQLite itself:
cursor.execute("SELECT name FROM sqlite_master")
rows = cursor.fetchall()
for row in rows:
sql = "SELECT ... FROM {} WHERE ...".format(row[0])
cursor.execute(sql)

Replacement for 'OR' in SphinxQL

I'm currently trying to integrate Sphinx search engine into Python application. The problem is that SphinxQL doesn't support OR clause as common SQL does. There are some hacks to use, like writing expressions in SELECT like this:
SELECT id,(field1 = val1 OR field2 = val2) as expr FROM foo_bar WHERE expr = 1;
However, it doesn't work with strings, because they should be handled using MATCH function. So I decided to divide query into separate subqueries and combine results obtained. Yet there's still a problem of getting a proper META information, especially the total_found field. Sphinx counts it for separate queries, but rows obtained from these queries may intersect and I have no ability to check it (database is large).
I believe there must be a solution. I'm using Sphinxit (SphinxAlchemy has a version conflict with SQLAlchemy I'm using).
Repost from SphinxSearch forum:
I have a table I need to search in with text and numerical columns as well. I need to
write a query with OR condition; found out that there's a way to do it using SELECT
expressions like:
SELECT *, quantity>=50 OR quantity=0 AS mycond FROM table1 WHERE mycond = 1;
Hopelessly it doesn't work with string attributes. This query isn't parsed:
SELECT *, category='foo' OR category='bar' AS mycond FROM table1 WHERE mycond = 1;
Yet this is working in Beta 2.2.3:
SELECT * FROM table1 WHERE category='foo';
What should I do to find count of rows that fit one of conditions, not every one of them?
I can make a few queries and merge obtained items into one list, but I need to now how
much of these rows are in the database now.
For attribute / facet OR'ing, I think you're correct that the only way is to put an expression in the SELECT clause.
For strings, though, check out the documentation on the fulltext query syntax. You can't exactly use the OR keyword, but something like this should work:
SELECT id, name
FROM recipes
WHERE MATCH('(#ingredients chocolate) | (#name cake)')
LIMIT 10;

How to structure a query with a large, complex where clause?

I have an SQL query that takes these parameters:
#SearchFor nvarchar(200) = null
,#SearchInLat Decimal(18,15) = null
,#SearchInLng Decimal(18,15) = null
,#SearchActivity int = null
,#SearchOffers bit = null
,#StartRow int
,#EndRow int
The variables #SearchFor, #SearchActivity, #SearchOffers can be either null or not null. #SearchInLat and #SearchInLng must both null, or both have values.
I'm not going to post the whole query as its boring and hard to read, but the WHERE clause is shaped like this:
( -- filter by activity --
(#SearchActivity IS NULL)
OR (#SearchActivity = Activities.ActivityID)
)
AND ( -- filter by Location --
(#SearchInLat is NULL AND #SearchInLng is NULL)
OR ( ... )
)
AND ( -- filter by activity --
#SearchActivity is NULL
OR ( ... )
)
AND ( -- filter by has offers --
#SearchOffers is NULL
OR ( ... )
)
AND (
... -- more stuff
)
I have read that this is a bad way to structure a query - that SqlServer has trouble working out an efficient execution plan with lots of clauses like this, so I'm looking for other ways to do it.
I see two ways of doing this:
Construct the query as a string in my client application, so that the WHERE clause only contains filters for the relevant parameters. The problem with this is it means not accessing the database through stored procedures, as everything else is at the moment.
Change the stored procedure so that it examines which arguments are null, and executes child procedures depending on which arguments it is passed. The problem here is that it would mean repeating myself a lot in the definition of the procs, and thus be harder to maintain.
What should I do? Or should I just keep on as I am currently doing? I have OPTION (RECOMPILE) set for the procedures, but I've heard that this doesn't work right in Server 2005. Also, I plan to add more parameters to this proc, so I want to make sure whatever solution I have is fairly scaleable.
The answer is to use DynamicSQL (be it in the client, or in an SP using sp_executesql), but the reason why is long, so here's a link...
Dynamic Search Conditions in T-SQL
A very short version is that one-size does not fit all. And as the optimiser creates one plan for one query, it's slow. So the solution is to continue using parameterised queries (for execution plan caching), but to have many queries, for the different types of search that can happen.
Perhaps an alternative might be to perform several separate select statements?
e.g.
( -- filter by activity --
if #SearchActivity is not null
insert into tmpTable (<columns>)
select *
from myTable
where (#SearchActivity = Activities.ActivityID)
)
( -- filter by Location --
if #SearchInLat is not null and #SearchInLng is not null
insert into tmpTable (<columns>)
select *
from myTable
where (latCol = #SearchInLat AND lngCol = #SearchInLng)
etc...
then select the temp table to return the final result set.
I'm not sure how this would work with respect to the optimiser and the query plans, but each individual select would be very straightforward and could utilise the indexes that you would have created on each column which should make them very quick.
Depending on your requirements it also may make sense to create a primary key on the temp table to allow you to join to it on each select (to avoid duplicates).
Look at the performance first, like others have said.
If possible, you can use IF clauses to simplify the queries based on what parameters are provided.
You could also use functions or views to encapsulate some of the code if you find you are repeating it often.

How to use strongly typed dataset designer to configure multiple updates?

I am using strongly-typed dataset as an ORM to wrap around my Microsoft Access database, now I am looking for a way to create an equivalent of
UPDATE table1
SET table1.nationality = 'england'
WHERE table1.nationality in (SELECT table2.nationality
FROM table2
WHERE table2.gender ='M');
In a strongly typed dataset designer, but not sure this is possible or not.
If this is not possible, what is the best way to accomplish this task? I am avoiding
Hand-code SQL
Stored procedures
as much as I can.
Edit: I am not saying that hand-code SQL is not permissible, just that it's not desirable. The same goes for stored procedures.
Like steven A low said.. but you use MS acces.. so params must be '?'
Right-click adapter and choose Add Query, select new Select/Update/SQL statement, then enter
UPDATE table1 SET
table1.nationality = ?
WHERE table1.nationality in (
select table2.nationality
from table2
where table2.gender = ?
)
give it an appropriate name, ie. updateNationalityByGender
updateNationalityByGender(string nationality, string gender)
are you using a table adapter?
if so, can you not just right-click and choose Add Query, select new Select/Update/SQL statement, then enter
UPDATE table1 SET
table1.nationality = #nationality
WHERE table1.nationality in (
select table2.nationality
from table2
where table2.gender = #gender
)
and give it an appropriate name? This should generate a table-adapter method like
updateNationalityByGender(string nationality, string gender)
you'll need to use the namespace for the table adapter to get access to it, e.g.
using your.name.space.datasetname.datasetnametableadapter;
LINQ to DataSet would be your best option.
1) Its all strongly typed.
2) You can use IQueryable/LINQ/lambda to query
3) You can bind to an Access database
Sql Express is free and it would be much better to use that. But if i was forced to use Access, this is how i'd do it.
http://msdn.microsoft.com/en-us/library/bb386977.aspx