Passing result of one table to another table in Database? - mysql

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;

Related

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.

mysql update with data from another table with join on two fields

I need to update 1 table with data from another where two fields match. I have a query but it's just locking up.
I have an employees_training_courses table
I have a company_training_categories table
I need to get the ID from company_training_categories where both the name and the account_id are the same in both tables.
So far I have this...
update employee_training_courses tc join company_training_categories ctc on ctc.name = tc.name AND ctc.account_id = tc.account_id set tc.company_training_category_id = ctc.id;
i can leave the query running, but it's clearly getting hung up somewhere !
This is your query:
update employee_training_courses tc join
company_training_categories ctc
on ctc.name = tc.name AND ctc.account_id = tc.account_id
set tc.company_training_category_id = ctc.id;
This is a very reasonable query. You probably just need indexes to speed it up. I would recommend:
create index idx_company_training_categories_2 on company_training_categories(name, account_id)
or even:
create index idx_company_training_categories_3 on company_training_categories(name, account_id, id)

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

JOIN/UPDATE TABLES WITH CONDITIONAL STATEMENT?

i have a registry table ( id , counter , group_name , type )
and group tables which includes these tables
software_group
website_group
news_group
etc ..
every group is in the registry table as well as it's own group table
now if i want to update a row in the registry i want appropriate group table to updated too
type column indicates the group table so i have it something like :
UPDATE registry JOIN
CASE WHEN registry.type = 1 THEN software_group
CASE WHEN registry.type = 2 THEN website_group
CASE WHEN registry.type = 3 THEN news_group
AS other_table
ON registry.id = other_table.reg_id
SET registry.name = $newname
,
other_table.name = $newname
WHERE registry.id = $id
is it possible to do something like this ? i can just select the registry row and do the job with php but i thought join/update would be faster than select/update
I think the dynamic join to tables on run time will be best if you handle the conditions in application layer, rather than the DB layer

Update with SELECT and group without GROUP BY

I have a table like this (MySQL 5.0.x, MyISAM):
response{id, title, status, ...} (status: 1 new, 3 multi)
I would like to update the status from new (status=1) to multi (status=3) of all the responses if at least 20 have the same title.
I have this one, but it does not work :
UPDATE response SET status = 3 WHERE status = 1 AND title IN (
SELECT title FROM (
SELECT DISTINCT(r.title) FROM response r WHERE EXISTS (
SELECT 1 FROM response spam WHERE spam.title = r.title LIMIT 20, 1)
)
as u)
Please note:
I do the nested select to avoid the famous You can't specify target table 'response' for update in FROM clause
I cannot use GROUP BY for performance reasons. The query cost with a solution using LIMIT is way better (but it is less readable).
EDIT:
It is possible to do SELECT FROM an UPDATE target in MySQL. See solution here
The issue is on the data selected which is totaly wrong.
The only solution I found which works is with a GROUP BY:
UPDATE response SET status = 3
WHERE status = 1 AND title IN (SELECT title
FROM (SELECT title
FROM response
GROUP BY title
HAVING COUNT(1) >= 20)
as derived_response)
Thanks for your help! :)
MySQL doesn't like it when you try to UPDATE and SELECT from the same table in one query. It has to do with locking priorities, etc.
Here's how I would solve this problem:
SELECT CONCAT('UPDATE response SET status = 3 ',
'WHERE status = 1 AND title = ', QUOTE(title), ';') AS sql
FROM response
GROUP BY title
HAVING COUNT(*) >= 20;
This query produces a series of UPDATE statements, with the quoted titles that deserve to be updated embedded. Capture the result and run it as an SQL script.
I understand that GROUP BY in MySQL often incurs a temporary table, and this can be costly. But is that a deal-breaker? How frequently do you need to run this query? Besides, any other solutions are likely to require a temporary table too.
I can think of one way to solve this problem without using GROUP BY:
CREATE TEMPORARY TABLE titlecount (c INTEGER, title VARCHAR(100) PRIMARY KEY);
INSERT INTO titlecount (c, title)
SELECT 1, title FROM response
ON DUPLICATE KEY UPDATE c = c+1;
UPDATE response JOIN titlecount USING (title)
SET response.status = 3
WHERE response.status = 1 AND titlecount.c >= 20;
But this also uses a temporary table, which is why you try to avoid using GROUP BY in the first place.
I would write something straightforward like below
UPDATE `response`, (
SELECT title, count(title) as count from `response`
WHERE status = 1
GROUP BY title
) AS tmp
SET response.status = 3
WHERE status = 1 AND response.title = tmp.title AND count >= 20;
Is using GROUP BY really that slow ? The solution you tried to implement looks like requesting again and again on the same table and should be way slower than using GROUP BY if it worked.
This is a funny peculiarity with MySQL - I can't think of a way to do it in a single statement (GROUP BY or no GROUP BY).
You could select the appropriate response rows into a temporary table first then do the update by selecting from that temp table.
you'll have to use a temporary table:
create temporary table r_update (title varchar(10));
insert r_update
select title
from response
group
by title
having count(*) < 20;
update response r
left outer
join r_update ru
on ru.title = r.title
set status = case when ru.title is null then 3 else 1;