Extbase query to compare two fields in same table - typo3

Is it possible to compare two database fields in the query api? For example I want compare the fields tstamp and crdate like:
SELECT * FROM tt_content WHERE tstamp > crdate;
In the query api I could not found a solution. To get all records and compare the fields in a loop is not a performed way, because this could be over 2 million records (in my real case).
Thanks for your help.

The only way I can think of (and that the query builder supports) is to directly supply the statement. It'll look like this:
$query = $contentElementRepository->createQuery();
$query->statement('SELECT * FROM tt_content WHERE tstamp > crdate');
$matchingContentElements = $query->execute();
This probably breaks the database abstraction layer, so use it with caution. statement() has a second parameter where you can put parameters, in case you need some user input in the query.
Maybe there is another way to do this which I don't know, I'd be really interested in it myself.

Related

How do I pass results from one Custom Query to another?

I am using Tableau to create custom queries, I need to pass the results from one custom query into another. So for example one custom query might have the following query:
select *
from bime.test_tab
where record_date = '2018-05-21'.
I then create another custom query which uses the results from the query above. Is this possible?
Sure you can by making this custom query as a subquery
select * from (select *
from bime.test_tab
where record_date = '2018-05-21') a
As you might already know that we do not have a leverage to use temp tables in Tableau custom queries, hence we usually create subqueries for that.
Considering your case,
SELECT BIM_TABLE.* FROM
(SELECT * FROM
BIME.TEST_TAB WHERE RECORD_DATE= '2018-05-21')BIM_TABLE
You can post your actual problem with the relevant columns if you need further help.
PS - It's advised to do most of your data manipulations in SQL itself (if you are running your workbook on live connection), as Tableau is not able to properly optimize part of the 'Custom SQL' query.

Apex query optimization

I am trying this query:
List<Account> onlyRRCustomer = [SELECT
ac.rr_First_Name__c,
ac.rr_Last_Name__c,
ac.rr_National_Insurance_Number__c,
ac.id,
ac.rr_Date_of_Birth__c
FROM
Account ac
WHERE
ac.rr_National_Insurance_Number__c IN :uniqueNiInputSet
AND RecordTypeId = :recordTypeId];
It gives me an error:
SELECT ac.rr_First_Name__c, ac.rr_Last_Name__c,
ac.rr_National_Insurance_Number__c, ac.id, ac.rr_Date_of_Birth__c FROM
Account ac WHERE (ac.rr_National_Insurance_Number__c = :tmpVar1 AND
RecordTypeId = :tmpVar2) 10:12:05.0
(11489528)|EXCEPTION_THROWN|[49]|System.QueryException: Non-selective
query against large object type (more than 200000 rows). Consider an
indexed filter or contact salesforce.com about custom indexing.
I understand uniqueNiInputSet.size() ~ 50, so, it's not an issue but for that record type, it might contains more records.
So, if i changed the position will that work? Means, first the recordtype and then the NIset in where clause. Is there any order how where clause are selected in SF. So, it will only look for 50 member and then within 50 it will serach for the particular record type?
That just means that the script is taking too long to execute. You may need to move this to a #future method or make execute it using Database.Batchable.
I don't think the order matters in SOQL, I think it's just trying to return too many records.
A non-selective query means you are performing a query against a table that has a large number of records and your query is not specific enough. You can work with Salesforce support to try to resolve this, either through the creation of additional backend indexes or by making the query more selective.
To be honest, your query looks very selective already, you're not using LIKE or IN. You should also put your most selective conditions first (resulting in a more focused query against your records).
I know it should'nt matter, but I would also move your conditions out of the parenthesis.
If there are any other fields you can filter on, that may help. Sometimes, you have to actually create new fields and populate them just to help make your queries more selective.
Also, if rr_National_Insurance_Number__c is a formula field, you will want to change it to a text field and populate workflow or apex instead. Formula fields require additional time on the servers to calculate.
SELECT rr_First_Name__c, rr_Last_Name__c, rr_National_Insurance_Number__c, id, rr_Date_of_Birth__c
FROM Account
WHERE new_custom_field__c = TRUE
AND rr_National_Insurance_Number__c = :tmpVar1
AND RecordTypeId = :tmpVar2
Your query is non-selective. For a standard indexes is 30% for the fist million records and 15% of records over a million up to 1 million records total. For and "AND" query each individual where criteria must itself be selective see this quick reference cheat sheet. In general try making
rr_National_Insurance_Number__c
an external id which will make it an indexed by salesforce by default and retry you query. Record Types are already indexed by default. If the result is still non-selective because of the number of results returned, try limiting the number of results using a field like CreatedDate to limit the scope of the query.

ormlite select count(*) as typeCount group by type

I want to do something like this in OrmLite
SELECT *, COUNT(title) as titleCount from table1 group by title;
Is there any way to do this via QueryBuilder without the need for queryRaw?
The documentation states that the use of COUNT() and the like necessitates the use of selectRaw(). I hoped for a way around this - not having to write my SQL as strings is the main reason I chose to use ORMLite.
http://ormlite.com/docs/query-builder
selectRaw(String... columns):
Add raw columns or aggregate functions
(COUNT, MAX, ...) to the query. This will turn the query into
something only suitable for using as a raw query. This can be called
multiple times to add more columns to select. See section Issuing Raw
Queries.
Further information on the use of selectRaw() as I was attempting much the same thing:
Documentation states that if you use selectRaw() it will "turn the query into" one that is supposed to be called by queryRaw().
What it does not explain is that normally while multiple calls to selectColumns() or selectRaw() are valid (if you exclusively use one or the other),
use of selectRaw() after selectColumns() has a 'hidden' side-effect of wiping out any selectColumns() you called previously.
I believe that the ORMLite documentation for selectRaw() would be improved by a note that its use is not intended to be mixed with selectColumns().
QueryBuilder<EmailMessage, String> qb = emailDao.queryBuilder();
qb.selectColumns("emailAddress"); // This column is not selected due to later use of selectRaw()!
qb.selectRaw("COUNT (emailAddress)");
ORMLite examples are not as plentiful as I'd like, so here is a complete example of something that works:
QueryBuilder<EmailMessage, String> qb = emailDao.queryBuilder();
qb.selectRaw("emailAddress"); // This can also be done with a single call to selectRaw()
qb.selectRaw("COUNT (emailAddress)");
qb.groupBy("emailAddress");
GenericRawResults<String[]> rawResults = qb.queryRaw(); // Returns results with two columns
Is there any way to do this via QueryBuilder without the need for queryRaw(...)?
The short answer is no because ORMLite wouldn't know what to do with the extra count value. If you had a Table1 entity with a DAO definition, what field would the COUNT(title) go into? Raw queries give you the power to select various fields but then you need to process the results.
With the code right now (v5.1), you can define a custom RawRowMapper and then use the dao.getRawRowMapper() method to process the results for Table1 and tack on the titleCount field by hand.
I've got an idea how to accomplish this in a better way in ORMLite. I'll look into it.

Should we use DBI bind or place holder for one parameter

I have a sql query like below
select id from table where name like 'somename';
Now there's only one record for this in db. Now with bind, sql query goes as below
my $sth = $dbh->prepare("select id from table where name=?");
$sth->execute('somename');
.... # fetch single row from array
So which one is better? with bind or without for single row?
Yes. Reason is very simple - using placeholders is good idea, and using it even for single argument makes it good practice. After some time, your hands will use placeholders even without thinking about it.

left join in zend framework

I am new in ZF and i would like to left join a table named country on country.id=firm_dtl.firm_country
$firmobj->fetchAll($firmobj->select($this)->where("firm_name like '$alpha%'")->order('firm_name'));
How can i do this.
I am trying with this code :-
$firmobj->select($this)->joinLeft(array("c"=>"country"), "c.id = firm_dtl.firm_country","c.name")->where("firm_name like '$alpha%'")->order('firm_name');
Here are some things that you can try to get the left join working and also to improve security.
I usually build my select statements across many lines and so I like to put it in a variable. To debug, I simply comment out the lines that I don't need.
$select = $firmobj->select()->from('country');
You'll want to setIntegrityCheck(false) because you probably won't be changing and committing the results from the query. Here's a quote from the ZF documentation about it.
The Zend_Db_Table_Select is primarily used to constrain and validate
so that it may enforce the criteria for a legal SELECT query. However
there may be certain cases where you require the flexibility of the
Zend_Db_Table_Row component and do not require a writable or deletable
row. for this specific user case, it is possible to retrieve a row or
rowset by passing a FALSE value to setIntegrityCheck().
$select->setIntegrityCheck(false);
Here is where you join. You can replace field1, field2, fieldn with the fields in the firm_dtl table that you want to see in the results.
$select->joinLeft(array('c' => 'country'), 'c.id = firm_dtl.firm_country', array('field1', 'field2', 'fieldn'));
Use parameter substitution to avoid SQL injection attacks.
$select->where('firm_name LIKE ?', "$alpha%");
And finally order the results and fetch the row set.
$select->order('firm_name');
$rowSet = $firmobj->fetchAll($select);
The 3rd parameter of joinLeft function should be an array of columns you want to fetch.
$firmobj->select($this)
->joinLeft(array("c"=>"country"), "c.id = firm_dtl.firm_country", array("c.name"))
->where("firm_name like '$alpha%'")
->order('firm_name');
Additionally, the better way is to use where function this way:
->where("firm_name like ?", $alpha . "%")
This way is the safer solution.