How to execute query with subqueries on a table and get a Rowset object as a result in Zend? - sql

I'm currently struggling on how to execute my query on a Table object in Zend and get a Rowset in return. Reason I need particularly THIS is because I'm modifying a code for existing project and I don't have much flexibility.
Query:
SELECT *
FROM `tblname` ud
WHERE ud.user_id = some_id
AND
(
(ud.reputation_level > 1)
OR
(
(SELECT COUNT( * )
FROM `tblname` t
WHERE t.user_id = ud.user_id
AND t.category_id <=> ud.category_id
AND t.city_id <=> ud.city_id
) = 1
)
)
Is there a way to describe this query using Select object?
Previous SQL solution was very simple and consisted of one WHERE clause:
$where = $this->getAdapter()->quoteInto("user_id = ?",$user_id);
return $this->fetchAll($where);
I need to produce same type of the result (so that it could be processed by existing code) but for more complicated query.
Things I've tried
$db = Zend_Db_Table::getDefaultAdapter();
return $db->query($sql)->fetchAll();
---------------- OR ----------------------
return $this->fetchAll($select);
---------------- OR ----------------------
return $this->_db->query($sql)->fetchAll();
But they either produce arrays instead of objects or fail with Cardinality violation message.
I would appreciate any help on how to handle SQL text queries in Zend.

$dbAdapter = Zend_Db_Table::getDefaultAdapter();
//change the fetch mode becouse you don't like the array
$dbAdapter->setFetchMode(Zend_Db::FETCH_OBJ);
$sql = "you're long sql here";
$result = $dbAdapter->fetchAll($sql);
Zend_Debug::dump($result);
exit;
For a list of all fetch modes go to Zend_Db_Adapter
To write you're query using Zend_Db_Select instead of manual string , look at Zend_Db_Slect

Related

How to exclude SQL variable in output

I have a complex SQL query where I have a few cases that use END AS variableName. I then use variableName to do some logic and then create a new variable which I want in the output result. However when I run the query, all the END AS variableNames that I have used are also outputted in the results.
Is there a way that I can exclude these variables as I only want the final variable that uses these variableNames.
Thanks
EDIT, here is a query explaining my problem
SELECT DISTINCT
mt.src_id AS “SRC_ID”,
CASE
WHEN mt.cd = ‘TAN’ THEN
(
(
SELECT SUM(src_amt)
FROM source_table st
WHERE mt.id = st.id
AND st._cd = ‘TAN’
AND st.amt_cd = ‘ABL’)
)
END AS src_amt
FROM MAIN_TABLE mt
WHERE
mf.dt >= 2021-12-12
AND SRC_AMT > 10
I need SRC_AMT to be used as some sort of logic but when I run the query, it prints out in the output as it's own column. I want to ignore this variable
you can wrap the whole thing into a new select-statement:
select SRC_ID from ( <entire previous query here> )

cfsavecontent display double apostrophe in SQL statement

I have several OR in my SQL statement so I want to save a chuck of it in a cfsavecontent. Here is that part:
<cfsavecontent variable="checkDepartment">
<cfif #wrkDept# EQ #dept[2][1]#>
Department = 'Health' AND
<cfelse>
Department = '#wrkDept#' AND
</cfif>
</cfsavecontent>
But the error I get on the page shows 2 sets of apostrophes around the word Health.
SQL
SELECT COUNT(*) AS numItems
FROM IT_PROJECTS
WHERE
Department = ''Health'' AND
status = 'Cancelled'
Can anyone help me to only get a single apostrophe? Thanks
So this answer seems a lot more complicated than it really is. And without knowing specifically what your query looks like (re:OR conditions), I'm not really sure how to structure it. It can be better. The goal should be to make one single trip to your SQL server with the query that makes the most sense for the data you're trying to get. I'm not sure what you are trying to do with cfsavecontent, but I don't think you need it.
The bulk of my example query (https://trycf.com/gist/4e1f46bfa84a6748aced0f9ee8221c6d/acf2016?theme=monokai) is setup. I chose to go with a cfscript format, because as Redtopia said, I also find it much easier to build a dynamic query in cfscript.
After initial setup, I basically just script out the variables I'll use in my final queryExecute().
// Base query.
qry = "SELECT count(*) AS theCount FROM IT_PROJECTS WHERE 1=1 " ;
// This is our dynamic filter that we build below.
qfilter = {} ;
// Query options.
opts = { "dbtype":"query" } ;
After we have our base, I build up the dynamic part of the query. This is the part that will likely change quite a bit depending on your current needs and setup.
For the first part, I basically replaced your cfif with a ternary evaluation. I'm not sure how your data plays into the evaluation of dept or where that array comes from. But from there I build a basic included statement of the query and set up the queryparam values for it. Then I add a second check that will pick a different set of values for the query (currently based on even/odd seconds). Again, I'm not sure of the intent of your query here, so I just made something dynamic.
//////////// BUILD DYNAMIC FILTER ////////////
qdept = ( wrkDept == dept[2][1] ) ? 'Health' : wrkDept ;
/// This one is an included filter:
qry &= " AND department = :dpt AND status = :sts " ;
qfilter.dpt = {"value":qdept,"cfsqltype":"CFSQLVARCHAR"} ;
qfilter.sts = {"value":"Cancelled","cfsqltype":"CFSQLVARCHAR"} ;
/// Adding Dynamic ORs
// Dynamically set status based on even/odd seconds.
qStatus = ( now().second()%2==0) ? "Cancelled" : "Active" ;
qry &= " OR ( department = :dpt2 AND status = :sts2 ) " ;
qfilter.dpt2 = {value:"IT",cfsqltype:"CFSQLVARCHAR"} ;
qfilter.sts2 = {value:qStatus,cfsqltype:"CFSQLVARCHAR"} ;
This gives us a SQL string that looks like:
SELECT count(*) AS theCount
FROM IT_PROJECTS
WHERE 1=1
AND department = :dpt AND status = :sts
OR
( department = :dpt2 AND status = :sts2 )
With a SQL statement, the placement of AND and OR conditions can greatly impact the results. Use parenthesis to group conditions how you need them.
After we've built the query string, we just have to plug it and our queryparams into the queryExecute().
result = queryExecute( qry , qfilter , opts ) ;
And if we want to output our data, we can go:
writeOutput("There are " & result.theCount & " records." ) ;
Which gives us:
There are 8 records.
Again, I don't know what your main conditions look like. If you can give me an example of a query with a bunch of ORs and ANDs, I'll try to modify this for you.

How to select from subquery using Laravel Query Builder?

I'd like to get value by the following SQL using Eloquent ORM.
- SQL
SELECT COUNT(*) FROM
(SELECT * FROM abc GROUP BY col1) AS a;
Then I considered the following.
- Code
$sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
$num = Abc::from(\DB::raw($sql))->count();
print $num;
I'm looking for a better solution.
Please tell me simplest solution.
In addition to #delmadord's answer and your comments:
Currently there is no method to create subquery in FROM clause, so you need to manually use raw statement, then, if necessary, you will merge all the bindings:
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
->count();
Mind that you need to merge bindings in correct order. If you have other bound clauses, you must put them after mergeBindings:
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
// ->where(..) wrong
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
// ->where(..) correct
->count();
Laravel v5.6.12 (2018-03-14) added fromSub() and fromRaw() methods to query builder (#23476).
The accepted answer is correct but can be simplified into:
DB::query()->fromSub(function ($query) {
$query->from('abc')->groupBy('col1');
}, 'a')->count();
The above snippet produces the following SQL:
select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`
The solution of #JarekTkaczyk it is exactly what I was looking for. The only thing I miss is how to do it when you are using
DB::table() queries. In this case, this is how I do it:
$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
'something',
DB::raw('sum( qty ) as qty'),
'foo',
'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();
Special atention how to make the mergeBindings without using the getQuery() method
From laravel 5.5 there is a dedicated method for subqueries and you can use it like this:
Abc::selectSub(function($q) {
$q->select('*')->groupBy('col1');
}, 'a')->count('a.*');
or
Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');
There are many readable ways to do these kinds of queries at the moment (Laravel 8).
// option 1: DB::table(Closure, alias) for subquery
$count = DB::table(function ($sub) {
$sub->from('abc')
->groupBy('col1');
}, 'a')
->count();
// option 2: DB::table(Builder, alias) for subquery
$sub = DB::table('abc')->groupBy('col1');
$count = DB::table($sub, 'a')->count();
// option 3: DB::query()->from(Closure, alias)
$count = DB::query()
->from(function ($sub) {
$sub->from('abc')
->groupBy('col1')
}, 'a')
->count();
// option 4: DB::query()->from(Builder, alias)
$sub = DB::table('abc')->groupBy('col1');
$count = DB::query()->from($sub, 'a')->count();
For such small subqueries, you could even try fitting them in a single line with PHP 7.4's short closures but this approach can be harder to mantain.
$count = DB::table(fn($sub) => $sub->from('abc')->groupBy('col1'), 'a')->count();
Note that I'm using count() instead of explicitly writing the count(*) statement and using get() or first() for the results (which you can easily do by replacing count() with selectRaw(count(*))->first()).
The reason for this is simple: It returns the number instead of an object with an awkwardly named property (count(*) unless you used an alias in the query)
Which looks better?
// using count() in the builder
echo $count;
// using selectRaw('count(*)')->first() in the builder
echo $count->{'count(*)'};
Correct way described in this answer: https://stackoverflow.com/a/52772444/2519714
Most popular answer at current moment is not totally correct.
This way https://stackoverflow.com/a/24838367/2519714 is not correct in some cases like: sub select has where bindings, then joining table to sub select, then other wheres added to all query. For example query:
select * from (select * from t1 where col1 = ?) join t2 on col1 = col2 and col3 = ? where t2.col4 = ?
To make this query you will write code like:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->from(DB::raw('('. $subQuery->toSql() . ') AS subquery'))
->mergeBindings($subQuery->getBindings());
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
During executing this query, his method $query->getBindings() will return bindings in incorrect order like ['val3', 'val1', 'val4'] in this case instead correct ['val1', 'val3', 'val4'] for raw sql described above.
One more time correct way to do this:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->fromSub($subQuery, 'subquery');
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
Also bindings will be automatically and correctly merged to new query.
I like doing something like this:
Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
GROUP BY `from_id` asc) as `sub`"))
->count();
It's not very elegant, but it's simple.
This works fine
$q1 = DB::table('tableA')->groupBy('col');
$data = DB::table(DB::raw("({$q1->toSql()}) as sub"))->mergeBindings($q1)->get();
I could not made your code to do the desired query, the AS is an alias only for the table abc, not for the derived table.
Laravel Query Builder does not implicitly support derived table aliases, DB::raw is most likely needed for this.
The most straight solution I could came up with is almost identical to yours, however produces the query as you asked for:
$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();
The produced query is
select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
->selectRaw('your subquery as somefield')
Deriving off mpskovvang's answer, here is what it would look like using eloquent model. (I tried updating mpskovvang answer to include this, but there's too many edit requests for it.)
$qry = Abc::where('col2', 'value')->groupBy('col1')->selectRaw('1');
$num = Abc::from($qry, 'q1')->count();
print $num;
Produces...
SELECT COUNT(*) as aggregate FROM (SELECT 1 FROM Abc WHERE col2='value' GROUP BY col1) as q1

PLSQL - Select works but Select within Where Clause returns no data

This is driving me crazy. I want to do simple comparison of a column and a variable but it just doesn't work. The QUERY 1 in following code returns me my value when i do a simple select, but i use the resulting variable in my 2nd query it just doesn't work..
It looks sooooo simple but I've been working on this for hours. The complete sql proc is
The big confusing thing is that if I replace v_bbg_symbol with some hard coded 'Value' (like 'FEDL01') it gives a correct answer for Query 2, but when I use the variable v_bbg_symbol it just doesn't work any more
Declare
v_bbg_symbol VARCHAR2(50);
V_OLD_INS_NAME Varchar2(50);
Begin
--QUERY 1
SELECT BBG_SYMBOL into v_bbg_symbol FROM quotes_external WHERE ID = 1;
--Gives output - 'FEDL01'
DBMS_OUTPUT.PUT_LINE('I got here:'||v_bbg_symbol||' is my value');
-QUERY 2
SELECT NAME INTO V_OLD_INS_NAME FROM INSTRUMENT
JOIN CURVE_INSTRUMENT ON
INSTRUMENT.INSTRUMENT_ID = CURVE_INSTRUMENT.INSTRUMENT_ID
JOIN GENERIC_INSTRUMENT ON
CURVE_INSTRUMENT.GENERIC_INSTRUMENT_ID = GENERIC_INSTRUMENT.GENERIC_INSTRUMENT_ID
WHERE CURVE_INSTRUMENT.CURVE_SNAPSHOT_ID =
(SELECT MAX(CURVE_INSTRUMENT.CURVE_SNAPSHOT_ID) FROM CURVE_INSTRUMENT)
AND GENERIC_INSTRUMENT.INSTRUMENT_NAME = v_bbg_symbol;
--ORACLE ERROR 'No Data Found'
DBMS_OUTPUT.PUT_LINE('I got here:'||V_OLD_INS_NAME||' is the new value');
END;
The first 'SELECT' gives me value which i select INTO a variable 'v_bbg_symbol', but when I use the same variable 'v_bbg_symbol' in my 2nd QUERY it pretends as if there is no value passed and does not return any result. If I give static value of 'v_bbg_symbol' i.e. ('FEDL01' in this case) in my 2nd QUERY, the results come as expected.
Please help..
Here is your query, with table aliases to facilitate following it:
SELECT NAME INTO V_OLD_INS_NAME
FROM INSTRUMENT i JOIN
CURVE_INSTRUMENT ci
ON i.INSTRUMENT_ID = ci.INSTRUMENT_ID JOIN
GENERIC_INSTRUMENT gi
ON ci.GENERIC_INSTRUMENT_ID = gi.GENERIC_INSTRUMENT_ID
WHERE ci.CURVE_SNAPSHOT_ID = (SELECT MAX(ci.CURVE_SNAPSHOT_ID) FROM CURVE_INSTRUMENT ci) and
gi.INSTRUMENT_NAME = v_bbg_symbol;
What this says is that the maximum ci.curve_snapshot_id is not for the instrument that is associated with v_bbg_symbol. I think you want a correlated subquery:
SELECT NAME INTO V_OLD_INS_NAME
FROM INSTRUMENT i JOIN
CURVE_INSTRUMENT ci
ON i.INSTRUMENT_ID = ci.INSTRUMENT_ID JOIN
GENERIC_INSTRUMENT gi
ON ci.GENERIC_INSTRUMENT_ID = gi.GENERIC_INSTRUMENT_ID
WHERE ci.CURVE_SNAPSHOT_ID = (SELECT MAX(ci2.CURVE_SNAPSHOT_ID)
FROM CURVE_INSTRUMENT ci2
WHERE ci2.instrument_id = i.instrument_id
) and
gi.INSTRUMENT_NAME = v_bbg_symbol;

Entity Framework, why is this sql being generated?

When I look at the SQL query generated by EF I see
SELECT [extent1].ID as ID,
[extent1].Name as Name
From(
Select myview.ID as ID,
myview.Name as Name
From myview) AS [extent1]
Where([Extent1].ID = #p_linq_0)
Why is the outside select happening on the inside select? I've got a very large table that I can get a record from easily with the outside query but the whole query combined times out.
My Linq query
var result = from i in invitationEntity.Invitations
.Where(a=>a.id == inviationId)
select i;
I am using SQL 2012 & EF5 & Linq.
Is there a way to "force" the simpler query?
Because you are calling "SELECT" once again at the end along with LINQ method.
var result = from i in invitationEntity.Invitations
.Where(a=>a.id == inviationId)
select i;
The last line select i, is useless, but EF is not aware of it whether it has anything useful or not, you can simply avoid it.
var result = invitationEntity.Invitations
.Where(a=>a.id == inviationId);
You can still enumerate result and get everything.
Ok sorry, I forgot to add, you don't have to use "from", you can simply use .Where(expression )
And if you want to use LINQ keywords, then you can use it this way,
var result = from i in invitationEntity.Invitations
where i.id == invitationId
select i;
You cannot mix LINQ keywords and LINQ extension methods.
i would say that
var result = from i in invitationEntity.Invitations
.Where(a=>a.id == inviationId)
select i;
this
a=>a.id == inviationId
from a=> generate
Select myview.ID as ID,
myview.Name as Name
From myview
so a is [extent1]
you should use a "standard" where clause
from i in invitationEntity.Invitations
where i.id == inviationId
select i;