Being DRY in a Sqlite query with CASE statement - sqlite

In the following (working) query:
SELECT q.id, q.section_id, q.type, q.required, q.condition,
CASE WHEN (t1.text_1 IS NULL) THEN
CASE WHEN ((SELECT t2.text_1 FROM translations t2 WHERE t2.item_id = q.id AND t2.item_model = 'questions' AND t2.language = 'en' LIMIT 1) IS NULL) THEN
(SELECT t3.text_1 FROM translations t3 WHERE t3.item_id = q.id AND t3.item_model = 'questions' LIMIT 1)
ELSE
(SELECT t2.text_1 FROM translations t2 WHERE t2.item_id = q.id AND t2.item_model = 'questions' AND t2.language = 'en' LIMIT 1)
END
ELSE
t1.text_1
END
AS translation
FROM questions q
LEFT JOIN translations t1 ON t1.item_id = q.id
AND t1.item_model = 'questions'
AND t1.language = 'fr'
ORDER BY q.position
You can see that the part (SELECT t2.text_1 FROM translations t2 WHERE t2.item_id = q.id AND t2.item_model = 'questions' AND t2.language = 'en' LIMIT 1) is repeated twice (the first to check if it's null, and the second to get the value).
Could the repeated same query a performance issue (I guess so)?
Is there a better way to rewrite this query, being DRY?

You can replace the inner CASE statement with coalesce() function:
coalesce(SELECT t2.text_1 FROM translations t2 WHERE t2.item_id = q.id AND t2.item_model = 'questions' AND t2.language = 'en' LIMIT 1,
SELECT t3.text_1 FROM translations t3 WHERE t3.item_id = q.id AND t3.item_model = 'questions' LIMIT 1)
From the documenation:
coalesce(X,Y,...)
The coalesce() function returns a copy of its first non-NULL argument,
or NULL if all arguments are NULL. Coalesce() must have at least 2
arguments.
Similar is the ifnull() function.

Related

Query Builder Error in doctrine symfony using where in

I have a raw query which I would like to convert into doctrine ORM. It's basically a query which contains sub query to calculate total count.
SELECT Count(*) AS total_count
FROM (SELECT *
FROM content_item_languages
WHERE default_content_item_id IN (SELECT id AS default_content_item_id
FROM content_item
WHERE content_type = 1
AND is_translated = 0
AND modified_on >=
'$timePeriodStart'
AND is_active = 1)
AND language_id = '$language') AS t
I have written below doctrine ORM but still I am getting error
$em = $this->getEntityManager()->createQueryBuilder();
$totalPostSubselect = $em->addSelect('c.id AS defaultContentItemId')
->from('AppBundle\Entity\ContentItem\ContentItem', 'c')
->andWhere('c.contentType = 1')
->andWhere('c.isTranslated = 0')
->andWhere('c.modifiedOn >= :timeperiod')
->andWhere('c.isActive = :status')
->setParameter('status', 1)
->setParameter('timeperiod', $timePeriodStart)->getDQL();
$em = $this->getEntityManager()->createQueryBuilder();
$defaultSubSelect = $em->addSelect(['*'])
->from('AppBundle\Entity\ContentItem\ContentItemLanguages', 'cl')
->andWhere("cl.defaultContentItemId IN ($totalPostSubselect)")
->andWhere('cl.languageId = :language')
->setParameter('subSelect', $totalPostSubselect)
->setParameter('language', $language)->getDQL();
$em = $this->getEntityManager()->createQueryBuilder();
$mainQuerySelect = $em->addSelect(["count(*) as total_count"])
->from("(".$defaultSubSelect.")", 'AS t')->getQuery();
return $mainQuerySelect->getResult();
Here is the error I got
[Doctrine\ORM\Query\QueryException] [Syntax Error] line 0, col 13: Error: Expected Literal, got '*'
[Doctrine\ORM\Query\QueryException]
SELECT count(*) as total_count FROM (SELECT * FROM
AppBundle\Entity\ContentItem\ContentItemLanguages cl
WHERE (
cl.defaultContentItemId IN (SELECT c.id AS defaultContentItemId
FROM AppBundle\Entity\ContentItem\ContentItem c WHERE
c.contentType = 1 AND
c.isTranslated = 0 AND
c.modifiedOn >= :timeperiod AND c.isActive = :status))
AND cl.languageId = :language) AS t
can anyone suggest, in exactly where I am doing wrong ?
In doctrine query language you can't SELECT *, instead you have to deal with objects. For your example something like:
$mainQuerySelect = $em->addSelect("count(t.id) as total_count")
->from("(".$defaultSubSelect.")", 'AS t')->getQuery();

Query filter assign sub query to one field value

I have stuck in this issue from the last two days.
Please help.
I want to assign the following query .
$qr = "( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = 'node' AND subconfigcode.deleted = '0') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = '1') AND (node.type IN ('offering')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0)";
to
one view's field value.
I have used the following code.
function general_views_query_alter(&$view, &$query) {
$qr = " ( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = 'node' AND subconfigcode.deleted = '0') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = '1') AND (node.type IN ('offering')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0)";
$query->add_where(1, "node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value", $qr);
}
But, it is returning the following where query.
where node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value = '( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = \'node\' AND subconfigcode.deleted = \'0\') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = \'1\') AND (node.type IN (\'offering\')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0) ')
I want to get query without the single quote assigned for sub query and remove extra slashed added to each value.
Please help.
Answer :
Direct query is not applicable for assignment purpose in the add_where condition.
For that, I have generated the query object using.
function general_views_query_alter(&$view, &$query) {
$subQuery = db_select('node', 'node'); $subQuery->leftJoin('field_data_field_select_parent_configuratio', 'select_parent_configuratio ', 'node.nid = select_parent_configuratio .entity_id');
$subQuery->condition('select_parent_configuratio.entity_type', 'node', '=');
$subQuery->condition('select_parent_configuratio.deleted', '0', '=');
$subQuery->leftJoin('node', 'select_parent_configuratio_node', 'select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid');
$subQuery->leftJoin('field_data_field_subconfigcode', 'subconfigcode', 'select_parent_configuratio_node.nid = subconfigcode.entity_id');
$subQuery->condition('subconfigcode.entity_type', 'node', '=');
$subQuery->condition('subconfigcode.deleted', '0', '=');
$subQuery->where("select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid");
$subQuery->condition('node.status', "1", '=');
$subQuery->condition('node.type', array('offering'), 'IN');
$subQuery->orderBy('configcode');
$subQuery->addField('subconfigcode', 'field_subconfigcode_value', 'configcode');
//$subQuery->range(0, 1);
$query->add_where($group,'node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value',$subQuery,'in');
}
Using this, I am able to generate it the query and assignment to value of the variable.

Android Sqlite Multiple Joins with Alias does not return anything

I have this query:
Cursor res = db.rawQuery("SELECT t1.Id, t2.EmpId FROM table1 t1
LEFT JOIN table2 t2 ON t1.t2Id = t2.Id
LEFT JOIN table3 t3 ON t1.t3Id = t3.Id
WHERE t1.Id = 90909", null);
Now when I go
if(res.moveToFirst()){
do{
MyObject obj = new MyObject();
obj.Id = res.getInt(res.getColumnIndex("t1.Id"));
MyObjectAsProperty objProp = new MyObjectAsProperty();
objProp.EmpId = res.getInt(res.getColumnIndex("t2.EmpId"));
}while(res.moveToNext());
}
The objProp.EmpId returns nothing (or 0). I looked at the cursor columns and it's Fields basically did not include the table alias names. How do I go about getting the values of those aliased fields?
Thanks!
EDIT
Apologies. I forgot to add that if for example it's referencing the same other table multiple times with the same field.
Here's updated query
Cursor res = db.rawQuery("SELECT t1.Id, t2.EmpId, t2b.EmpId FROM table1 t1
LEFT JOIN table2 t2 ON t1.t2Id = t2.Id
LEFT JOIN table2 t2b ON t1.t2bId = t2b.Id
WHERE t1.Id = 90909", null);
if(res.moveToFirst()){
do{
MyObject obj = new MyObject();
obj.Id = res.getInt(res.getColumnIndex("t1.Id"));
MyObjectAsProperty objProp = new MyObjectAsProperty();
objProp.EmpId = res.getInt(res.getColumnIndex("t2.EmpId"));
MyObjectAsProperty objProp2 = new MyObjectAsProperty();
objProp2 .EmpId = res.getInt(res.getColumnIndex("t2bId.EmpId"));
}while(res.moveToNext());
}
The documentation says:
The name of a result column is the value of the "AS" clause for that column, if there is an AS clause. If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next.
So you must use AS:
SELECT t1.Id AS ObjID, t2.EmpId AS EmpId, ...

pl/sql : execute immediate update?

V_SQL4 := 'UPDATE EMP_TABLE m
Set m.name = mft.name,
m.age = mft.age,
m.dept = mft.dept,
Where m.id = mft.id and
(m.name != mft.name Or
m.age != mft.age Or
m.dept != mft.dept )';
DBMS_OUTPUT.PUT_LINE(V_SQL4);
EXECUTE IMMEDIATE V_SQL4;
How and where to declare the temporary table EMP_TMPas mft in the statement?
If i look into the requirement i dont see requirment of PL/SQL in
this. A better approach woould be using Merge. I have illuistrated an
example below. If Dynamic SQL is not hard and bound you can use this
too. Let me know if this helps.
MERGE INTO EMP_TABLE m USING EMP_TMP mft
ON (m.id = mft.id AND (m.name != mft.name OR m.age != mft.age OR m.dept != mft.dept))
WHEN MATCHED THEN
UPDATE SET
m.name = mft.name,
m.age = mft.age,
m.dept = mft.dept;
This SO post has an answer to a similar question.
In your case, the query would transform as below
V_SQL4 := 'UPDATE EMP_TABLE m
SET (name, age, dept) = (SELECT mft.name
,mft.age
,mft.dept
FROM EMP_TMP mft
WHERE m.id = mft.id
AND m.name != mft.name Or
AND m.age != mft.age Or
AND m.dept != mft.dept
)
WHERE EXISTS (
SELECT 1
FROM EMP_TMP mft
WHERE m.id = mft.id
)';

combine multiple queries into single query

I have 2 queries and calling a function 2 times I need call the function one time only based on msg_sys_no count and msg_trans_type.
please find the queries mentioned below and provide me the solution for merging into single.
SELECT COUNT(DISTINCT b1.msg_sys_no) INTO A
FROM tra_message b1
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_service_provider = in_svc_provider
AND b1.msg_trans_type = 'TRADE1'
AND get_transaction_status_func(b1.msg_sys_no, b1.msg_trans_type) = 'S';
SELECT COUNT(DISTINCT b1.msg_sys_no) INTO B
FROM tra_message b1
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_service_provider = in_svc_provider
AND b1.msg_trans_type = 'TRADE2'
AND get_transaction_status_func(b1.msg_sys_no, b1.msg_trans_type) = 'S';
What about something like this:
WITH tra_data
AS (SELECT *
FROM tra_message
WHERE TO_CHAR (msg_when_created, 'YYYY-MM-DD') = in_start_date
AND msg_service_provider = in_svc_provider
AND get_transaction_status_func (msg_sys_no, msg_trans_type) =
'S')
SELECT COUNT (*)
FROM tra_data
WHERE msg_trans_type = 'TRADE1'
UNION
SELECT COUNT (*)
FROM tra_data
WHERE msg_trans_type = 'TRADE2'
The problem is your AND b1.msg_trans_type IN ('TRADE1','TRADE2') condition.
Try something like this:
select COUNT(DISTINCT a) TRADE1,
COUNT(DISTINCT b) TRADE2
into A,B
from (
select case when b1.msg_trans_type = 'TRADE1'
then b1.msg_sys_no
else null end as a,
case when b1.msg_trans_type = 'TRADE2'
then b1.msg_sys_no
else null end as b
FROM tra_message b1
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_service_provider = in_svc_provider
AND b1.msg_trans_type IN ('TRADE1','TRADE2')
AND get_transaction_status_func(b1.msg_sys_no, b1.msg_trans_type) = 'S'
);

Resources