MYSQL SELECT in SELECT query with large data: request timed out - mysql

The following query working well with small amount of data, but with larga data, I get 1001 The request timed out error.
I need this query before I want to order by switch.
Can anybody some better solution?
SELECT t.azon,
parent_id,
tul,
nev,
szures,( SELECT EXISTS (
SELECT *
FROM 1_tulajdonsagkoto tk
WHERE tk.tulajdonsag_id = t.azon AND tk.termek_id = 1238 LIMIT 1)) AS switch
FROM 1_tulajdonsagok t
LEFT JOIN 1_tulajdonsagkat k ON t.parent_id = k.azon

(SELECT EXISTS
(SELECT *
FROM 1_tulajdonsagkoto tk
WHERE tk.tulajdonsag_id = t.azon
AND tk.termek_id = 1238
LIMIT 1)) AS SWITCH
This make N+1 query problem. So we have 2 solutions:
Move this into another query in codes. And you can map the "SWITCH" value in codes.
Move this query into a temporary table before main query, and then left join main query into the temporary table.

Related

Passing result of one table to another table in Database?

I have the following scenario: I am trying to pass result of one query to another , In this case I am trying to pass view_id in another query since this are ids they are unique and cant be duplicate in any case .
select view_id from view where view_query_id = "18711987173"
select queue_id from queue where queue_view = view_id
`
I saw some examples and I tried executing them something like as
select view_id from view where view_query_id = "18711987173 exists (select queue_id from queue where queue_view = view.view_id)
But surely this didnt helped :)
You can use a common table expression
WITH temp AS (SELECT view_id FROM view WHERE view_query_id = "18711987173")
SELECT queue_id FROM queue q INNER JOIN temp t ON q.queue_id = t.view_id;
This should work regardless of what relationship is between those tables. You can replace the JOIN by WHERE..IN, but this way seems cleaner and takes care if the no. of values in IN becomes too large.
Use table expression
WITH temp AS (SELECT view_id FROM view WHERE view_query_id = "18711987173")
SELECT queue_id FROM queue q INNER JOIN temp t ON q.queue_id = t.view_id;

SQL subquery with reference to parent table gives "Unknown column 'test_results.id' in 'where clause'"

First off, take a look at diagram (this is an application for testing students knowledge)
I already have working application, which calculates score (in percents), but to sort by score, it is required to select all the records (of current test). And it drastically slows down app (~ 10 seconds of waiting). So I decided to move that logic into single sql query.
Now, my SQL query looks like this:
select test_results.*,
(
select test_result_total_score * 100 / test_result_total_max_score
from (
select (select sum(question_score)
from (
select question_total_right_answers = question_total_options as question_score
from (
select (
select count(*)
from answers
inner join answer_options on answer_options.id = answers.answer_option_id
where answers.asked_question_id = asked_questions.id
and answers.is_chosen = answer_options.is_right
) as question_total_right_answers,
(
select count(*)
from answers
left join answer_options on answer_options.id = answers.answer_option_id
where answers.asked_question_id = asked_questions.id
) as question_total_options
from asked_questions
where asked_questions.test_result_id = test_results.id
) as rigt_per_question
) as questions_scores) as test_result_total_score,
(select count(*)
from asked_questions
where asked_questions.test_result_id = test_results.id) as test_result_total_max_score
) as right_per_test_result
) as result_in_percents
from test_results
where test_results.id between 1 and 200;
Here is what it should do: for each asked question collect how many answer options there are (question_total_options) and how many answers user selected right (question_total_right_answers) - the very nested subqueries.
Then for each of this results calculate score (this is basically 1 if user selected all right options and 0 if at least one option is selected not right).
After that, we sum scores of all that questions (test_result_total_score - how many questions user answered right). Also, we calculate how many questions there are in test result (test_result_total_max_score).
With that information we can calculate percentage of right answered questions (test_result_total_score * 100 / test_result_total_max_score)
And the error is on lines 23 and 28:
where asked_questions.test_result_id = test_results.id
where asked_questions.test_result_id = test_results.id) as test_result_total_max_score
It says: [42S22][1054] Unknown column 'test_results.id' in 'where clause'
I have tried using variable #test_result_id like this:
select test_results.*,
#test_result_id := test_results.id,
( ... )
where asked_questions.test_result_id = #test_result_id
where asked_questions.test_result_id = #test_result_id) as test_result_total_max_score
And it evaluates, but in wrong way (probably because order of evaluation select values is undefined). BTW, all result_in_percents correspond to very first result.
For those facing similar problem, it seems that there is no simple solution.
First off, you can try rewrite your subqueries with joins as I did (see below). But when you would like to perform group operations on grouped results, you are really unhappy person). A "dirty" solution might be create function to overcome barrier of nesting subqueries.
create function test_result_in_percents(test_result_id bigint unsigned)
returns float
begin
return (
select sum(tmp.question_right) * 100 / count(*)
from (select sum(answers.is_chosen = answer_options.is_right) = count(*) as question_right
, asked_questions.test_result_id as test_result_id
from answers
inner join answer_options on answer_options.id = answers.answer_option_id
inner join asked_questions on asked_questions.id = answers.asked_question_id
where asked_questions.test_result_id = test_result_id
group by answers.asked_question_id
) as tmp
group by test_result_id
);
end;
And then, just use this function:
select (test_result_in_percents(test_results.id)) as `result_percents`
from `test_results`
where `test_results`.`test_id` = 181
and `test_results`.`test_id` is not null
order by `test_results`.`id` desc;

INNER JOIN query

I'm having trouble optimising a simple SQL query but having serious issue with timing. I've written it three times and none of them work. Here is the original one I was hoping to work:
SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR
INNER JOIN (
SELECT DISTINCT COVER_RISK_ID
FROM EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
INNER JOIN
(SELECT DISTINCT CONTACT_ID, FOLLOW_UP_DATE
FROM EDW_STG.STG_CIM_SVOM03
WHERE OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address') ADDR_WF
ON RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
WHERE RSKMASTER.IS_STORNO != 1
AND RSKMASTER.PRODUCT_CODE = 'HOME'
AND ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE
AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'
AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE
) ACTVRSK
ON ACTVRSK.COVER_RISK_ID = RSKADDR.RISK_ID
The code in the first inner join works fast all the way to the end. That is, the second SELECT query (within the INNER JOIN query of the first and main SELECT query) works fast without a problem. The problem arises when I integrate the second SELECT query inside the INNER JOIN of the main SELECT query (select RSKADDR.*).
Then it seems the execution is never ending!
I tried other ways and same result:
SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR
INNER JOIN EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
ON RSKMASTER.COVER_RISK_ID = RSKADDR.RISK_ID
AND RSKMASTER.IS_STORNO != 1
AND RSKMASTER.PRODUCT_CODE = 'HOME'
AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'
INNER JOIN EDW_STG.STG_CIM_SVOM03 ADDR_WF
ON OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address'
AND RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
AND ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE
AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE
It's such an easy query and can't get it to work. How can I do this?
DISTINCT is a costly operation and seldom needed. It often indicates a bad database design or a poorly written query. In your query you are even doing this repeatedly; that doesn't look good.
The second query looks much better. As you say you get the same result, DISTINCT in the first query was superfluous obviously.
I see you doing joins, but all you select is data from one table. So why join then? Select from the table you want data from and put your criteria in WHERE where it belongs.
The following query may be faster, because it plainly shows that we are simply checking whether we find matches in the other tables or not. But then, MySQL was known for not performing too well with IN clauses, so that may depend on the Version you are using.
select *
from edw_base.rci_risk_address
where risk_id in
(
select rm.cover_risk_id
from edw_base.rci_cover_risk_master rm
where rm.is_storno <> 1
and rm.product_code = 'HOME'
and rm.policy_status_code = 'POLICY'
and exists
(
select *
from edw_stg.stg_cim_svom03 adr
where adr.contact_id = rm.contact_code
and adr.follow_up_date >= rm.cover_eff_start_date
and adr.follow_up_date <= rm.cover_eff_end_date
and adr.outstanding = 1
and adr.queue = 'CIM Update for Contact Address'
)
);
Anyway, with your second query or with mine, I suppose the following indexes would help:
create index idx1 on rci_cover_risk_master
(
product_code,
policy_status_code,
is_storno,
contact_code,
cover_eff_start_date,
cover_eff_end_date,
cover_risk_id
);
create index idx2 on stg_cim_svom03
(
contact_id,
follow_up_date,
outstanding,
queue
);
create index idx3 on rci_risk_address(risk_id);
From the query, you only need RSKADDR data, so no need for an INNER JOIN. You can do the same with EXISTS keyword. Try the below query
SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR
WHERE EXISTS (
SELECT 1
FROM EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
WHERE EXISTS
(SELECT 1
FROM EDW_STG.STG_CIM_SVOM03
WHERE OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address') ADDR_WF
AND RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
AND RSKMASTER.IS_STORNO != 1
AND RSKMASTER.PRODUCT_CODE = 'HOME'
AND ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE
AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'
AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE
)
AND RSKMASTER.COVER_RISK_ID = RSKADDR.RISK_ID
)
Note : I have not tested query as no schema available.

Retrieving rows that have 2 columns matching and 1 different

Below is my table called 'datapoints'. I am trying to retrieve instances where there are different instances of 'sensorValue' for the same 'timeOfReading' and 'sensorNumber'.
For example:
sensorNumber sensorValue timeOfReading
5 5 6
5 5 6
5 6 10 <----same time/sensor diff value!
5 7 10 <----same time/sensor diff value!
Should output: sensorNumber:5, timeOfReading: 10 as a result.
I understand this is a duplicate question, in fact I have one of the links provided below for references - however none of the solutions are working as my query simply never ends.
Below is my SQL code:
SELECT table1.sensorNumber, table1.timeOfReading
FROM datapoints table1
WHERE (SELECT COUNT(*)
FROM datapoints table2
WHERE table1.sensorNumber = table2.sensorNumber
AND table1.timeOfReading = table1.timeOfReading
AND table1.sensorValue != table2.sensorValue) > 1
AND table1.timeOfReading < 20;
Notice I have placed a bound for timeOfReading as low as 20. I also tried setting a bound for both table1 and table 2 as well but the query just runs until timeout without displaying results no matter what I put...
The database contains about 700mb of data, so I do not think I can just run this on the entire DB in a reasonable amount of time, I am wondering if this is the culprit?
If so how could I properly limit my query to run a search efficiently? If not what am doing wrong that this is not working?
Select rows having 2 columns equal value
EDIT:
Error Code: 2013. Lost connection to MySQL server during query 600.000 sec
When I try to run the query again I get this error unless I restart
Error Code: 2006. MySQL server has gone away 0.000 sec
You can use a self-JOIN to match related rows in the same table.
SELECT DISTINCT t1.sensorNumber, t1.timeOfReading
FROM datapoints AS t1
JOIN datapoints AS t2
ON t1.sensorNumber = t2.sensorNumber
AND t1.timeOfReading = t2.timeOfReading
AND t1.sensorValue != t2.sensorValue
WHERE t1.timeOfReading < 20
DEMO
To improve performance, make sure you have a composite index on sensorNumber and timeOfReading:
CREATE INDEX ix_sn_tr on datapoints (sensorNumber, timeOfReading);
I think you have missed a condition. Add a not condition also to retrieve only instances with different values.
SELECT *
FROM new_table a
WHERE EXISTS (SELECT * FROM new_table b
WHERE a.num = b.num
AND a.timeRead = b.timeRead
AND a.value != b.value);
you can try this query
select testTable.* from testTable inner join (
SELECT sensorNumber,timeOfReading
FROM testTable
group by sensorNumber , timeOfReading having Count(distinct sensorValue) > 1) t
on
t.sensorNumber = testTable.sensorNumber and t.timeOfReading = testTable.timeOfReading;
here is sqlFiddle
This query will return the sensorNumber and the timeOfReading where there are different values of sensorValue:
select sensorNumber, timeOfReading
from tablename
group by sensorNumber, timeOfReading
having count(distinct sensorValue)>1
and this will return the actual records:
select t.*
from
tablename t inner join (
select sensorNumber, timeOfReading
from tablename
group by sensorNumber, timeOfReading
having count(distinct sensorValue)>1
) d on t.sensorNumber=d.sensorNumber and t.timeOfReading=d.timeOfReading
I would suggest you to add an index on sensorNumber, timeOfReading
alter table tablename add index idx_sensor_time (sensorNumber, timeOfReading)

Mysql, combining and querying results with sub queries or temp tables

I am running into some trouble with the following circumstances:
I have a query that creates two temp tables, and the following select to join them together--
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId
I am then trying to create another column from concatenating a few of the resulting fields and then use that to reference/query against another table. Is there a way to accomplish this in one query? Should I get away from the temp tables?
Thank you again in advance.
update: If I try to alias the combination of the two temp tables I get an error message stating [Err] 1060 - Duplicate column name 'packetDetailsId'
select * from (
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId) as myalias
Another Update: I almost have it working as one query but I get the result "(BLOB)" in the column I concoctenated:
select packet_details.packetDetailsId,products.productId,Credit,AccountNum,OrderStat, CONCAT(products.productId,Credit,'_',OrderStat) as consol from (
select packetDetailsId, GROUP_CONCAT(Credit) AS Credit, GROUP_CONCAT(AccountNum) AS AccountNum, GROUP_CONCAT(OrderStat) AS OrderStat FROM
( SELECT pd_extrafields.packetDetailsId,
CASE WHEN pd_extrafields.ex_title LIKE ('%Credit%')
THEN pd_extrafields.ex_value ELSE NULL END as Credit,
CASE WHEN pd_extrafields.ex_title LIKE ('%Account%')
THEN pd_extrafields.ex_value ELSE NULL END as AccountNum,
CASE WHEN pd_extrafields.ex_title LIKE ('%Existing%')
THEN pd_extrafields.ex_value ELSE NULL END as OrderStat
FROM pd_extrafields )AS TempTab GROUP BY packetDetailsId ) as alias2
INNER JOIN packet_details ON alias2.packetDetailsId = packet_details.packetDetailsId
INNER JOIN sales ON packet_details.packetDetailsId = sales.packetDetailsId
INNER JOIN sold_products ON sales.saleId = sold_products.saleId
INNER JOIN products ON sold_products.productId = products.productId
If I understand correctly, you already have the temporary tables created and you need to "concatenate" the results, using from ... inner join ...
The only possible restriction you may have is that you can only reference your temporary tables once in your from clause; besides that, there are no other restrictions (I frequently use temporary tables as intermediate steps in the creation of my final result).
Tips
Let's say your temp tables are temp_result1 and temp_result2. Both tables have a field packedDetailsId, on which the join will be performed. Remember to create the appropriate indexes on each table; at the very least you need to index packedDetailsId on both tables:
alter table temp_result1
add index PDI(packedDetailsId);
alter table temp_result2
add index PDI(packedDetailsId);
Now, just execute a query with the desired join and concatenation. If concat returns BLOB, then cast the result as char (of course, I'm assuming you need a text string):
select r1.*, r2.*, cast(concat(r1.field1, ',', r2.field2) as char) as data_concat
from temp_result1 as r1
inner join temp_result2 as r2 on r1.packedDetailsId = r2.packedDetailsId;
I see your problem is that GROUP_CONCAT is returning BLOB values... It's normal (MySQL doesn't know a priori how to return the values, so it returns binary data); just use the cast function.
Hope this helps you
so, if the result2 and result are both temp tables, you will have to include the # if local temp table and ## if global temp table
so your statements should be :
SELECT * FROM #result
INNER JOIN #result2 ON #result2.packetDetailsId = #result.packetDetailsId
My Bad. This is only applicable for MS SQL