inner join and count records recursively - mysql

I have two tables named Topics and DocumentTopics
Topics table has the following structure
di_name | parentTopic
the records in Topics can be either a main or a child topic of a main topic. If a record is a main topic then the value of parentTopic will be null.
DocumentsTopics has the following structure
doc_name | topic_di_name
documentsTopics holds the records of all my documents by name and their topics. I can join both tables using topics->di_name and documentTopics->topic_di_name
SELECT t1.topic_di_name, count(t1.topic_di_name) as count
FROM DocumentsTopics t1
INNER JOIN Topics t2
ON t1.topic_di_name = t2.di_name
GROUP BY t1.topic_di_name;
but what I actually want to is group the topics by main topics only and get a sum count of all the records under the main topic and all its children's topics. These may drill down to more than one level.
here is a schema with sample data
There are 2 main topics but only one has siblings. The total count I am looking for is for the main topics only but they should include the counts of all the sibling topics within.
I am guessing the only way to do that is to run a recursive function but I am unsure about how to do that with a single SQL query. Is it even possible?
Any help would be greatly appreciated

Here's another way to do it using a UNION in a sub query in case this makes more sense to anyone:
SELECT `der`.`parentTopic`,
SUM(IF(`dt`.`topic_di_name` = `der`.`subTopic`,1,0)) AS `counter`
FROM (
SELECT `parentTopic`,
`di_name` AS `subTopic`
FROM `topics`
WHERE `parentTopic` IS NOT NULL
UNION
SELECT `di_name` AS `parentTopic`,
`di_name` AS `subTopic`
FROM `topics`
WHERE `parentTopic` IS NULL) AS `der`
JOIN `documentsTopics` AS `dt` ON `dt`.`topic_di_name` = `der`.`subTopic`
GROUP BY `der`.`parentTopic`
;
Here's this answer in sql fiddle.
Hope this helps!

Why can't you use:
SELECT t3.parent_key, count(t3.parent_key)
FROM DocumentsTopics t1
INNER JOIN Topics t2
ON t1.topic_di_name = t2.di_name
LEFT JOIN (select *, coalesce(parentTopic, di_name) parent_key from Topics) t3
ON t2.di_name = t3.di_name
GROUP BY t3.parent_key

Something like this should work for two levels.
https://www.db-fiddle.com/f/vcjUtUfxsn4yaKnQhmQJ6d/5
SELECT IFNULL(t.parentTopic,t.di_name) AS main_topics,COUNT(*) AS counter
FROM DocumentsTopics d
INNER JOIN Topics t ON d.topic_di_name=t.di_name
GROUP BY 1

I think this will work in mySql 8.0 and give you nested results more than one level deep, but I don't have access to test
with recursive cte as (
SELECT `parentTopic`,
`di_name`
FROM `topics`
WHERE `parentTopic` IS NOT NULL
union all
select
`parentTopic`,
`di_name`
from `topics` t2
inner join cte on t2.`parentTopic` = cte.`di_name`
)
select * from cte

Related

Mysql - I have 3 unique tables, need a hint on getting the details with the count

I have 3 tables which are interconnected and i want to select columns from two tables and counts from table 3. If anyone is aware on this, any hint would be appreciated.
Below is the sql i tried, but the count is getting repeated
SELECT distinct p.p_id, p.p_f6, p.p_l4,m.m_id, (
SELECT COUNT(*)
FROM ttokens t where t.pdetail_id = p.pdetail_id
) AS token_count
FROM tparking p,ttokens t LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
WHERE t.pdetail_id = p.pdetail_id
You can try to use JOIN with subquery to get your count instead of selcet subquery.
SELECT p.p_id, p.p_f6, p.p_l4,m.m_id,t.cnt
FROM tparking p
JOIN (
SELECT pdetail_id,COUNT(*) cnt
FROM ttokens
GROUP BY pdetail_id
) t ON t.pdetail_id = p.pdetail_id
LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
Note
I would use JOIN instead of , comma with where condition to connect two tables,, is an old style.

MySQL nested join across many tables

I have table for transactions, transaction_properties, transaction_inventories. inventories.
`transactions:`
id, name, qty
`transaction_properties:`
transaction_id, property_id
`transaction_inventory:`
transaction_id, inventory_id
`inventories:`
id, name, property_id
My task is to get all transaction according my property id.
property_id gets data from inventory that gets data from transaction_inventory, also gets data from transaction_properties and finally I get all transaction_ids to get them from transaction table.
Please do not consider to change table architecture. This style is a must for this project.
Check the following query:
select inv.*,t.*,tran_pro.*,tran_inv.* from inventories as inv
left join on transation as t on t.id on tran_pro.transtaion_id
left join on transaction_properties as tran_pro on t.id = tran_pro.transaction_id
left join on transaction_invertory as tran_inv on t.id = tran_inv.transaction_id
where inv.property_id = ''
Note:Keep all ids as primary key
I don't know, it should be fairly simple if you have attempted to solve the problem or looked up how joins work. Unless I am missing any other detail.
select t.id, t.name, invt.id, tp.property_id
from inventories invt
inner join transactions_inventory ti
on invt.id = ti.inventory_id
inner join transaction_properties tp
on tp.transaction_id = ti.transaction_id
inner join transactions t
on t.id = tp.transaction_id

How to optimize multiple sub-queries from multiple tables?

I have two Table such as tnx_lc_invoice and tnx_lc_payment. I want to generate report from this two tables.
Table schema like below images
tnx_lc_payment
tnx_lc_invoice
I want to generate output like below images
output
I am trying below query and its generate similar output. but i want to optimize this query or any alternative solution for faster result.
SELECT
a.lc_no,
a.invoiceValue,
b.paymentValue,
(
a.invoiceValue - b.paymentValue
) AS shortPaymentValue
FROM
(
SELECT
lc_no,
sum(invoice_value) AS invoiceValue
FROM
tnx_lc_invoice
GROUP BY
lc_no
) a
INNER JOIN (
SELECT
lc_no,
sum(payment_value) AS paymentValue
FROM
tnx_lc_payment
GROUP BY
lc_no
) b ON a.lc_no = b.lc_no
If any other alternative easy solution please let me know.Thanks in advance.
Instead of using subqueries create an inner direct between them
SELECT
a.lc_no,
sum(a.invoice_value) AS invoiceValue,
sum(b.payment_value) AS payment_value,
(sum(a.invoice_value) - sum(b.paymentValue)) AS shortPaymentValue
FROM tnx_lc_invoice a
INNER JOIN tnx_lc_payment b
ON a.lc_no = b.lc_no
GROUP BY
a.lc_no
The query was not correct because it multiply the rows if both invoice and payments are duplicated on the same lc_no.
So it is necessary to add at least one group by in an inner query.
SELECT
a.lc_no,
sum(a.invoice_value) AS invoiceValue,
sum(b.payment_value) AS payment_value,
sum(a.invoice_value) - sum(b.payment_Value) AS shortPaymentValue
FROM (select lc_no, sum(invoice_value) as invoice_value
from tnx_lc_invoice group by lc_no) a
INNER JOIN tnx_lc_payment b
ON a.lc_no = b.lc_no
GROUP BY
a.lc_no

Creating a subquery in Access

I am attempting to create a subquery in Access but I am receiving an error stating that one record can be returned by this subquery. I am wanting to find the top 10 companies that have the most pets then I want to know the name of those pets. I have never created a subquery before so I am not sure where I am going wrong. Here is what I have:
SELECT TOP 10 dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgency
(SELECT dbo_tPet.Pet
FROM dbo_tPet)
FROM dbo_tPet INNER JOIN dbo_tGovenrnmentRegulatoryAgency ON
dbo_tPet.GovernmentRegulatoryAgencyID =
dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgencyID
GROUP BY dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgency
ORDER BY Count(dbo_tPet.PetID) DESC;
Consider this solution, requiring a subquery in the WHERE IN () clause:
SELECT t1.GovernmentRegulatoryAgency, dbo_tPet.Pet,
FROM dbo_tPet
INNER JOIN dbo_tGovenrnmentRegulatoryAgency t1 ON
dbo_tPet.GovernmentRegulatoryAgencyID = t1.GovernmentRegulatoryAgencyID
WHERE t1.GovernmentRegulatoryAgency IN
(SELECT TOP 10 t2.GovernmentRegulatoryAgency
FROM dbo_tPet
INNER JOIN dbo_tGovenrnmentRegulatoryAgency t2 ON
dbo_tPet.GovernmentRegulatoryAgencyID = t2.GovernmentRegulatoryAgencyID
GROUP BY t2.GovernmentRegulatoryAgency
ORDER BY Count(dbo_tPet.Pet) DESC);
Table aliases are not needed but I include them for demonstration.
This should hopefully do it:
SELECT a.GovernmentRegulatoryAgency, t.NumOfPets
FROM dbo_tGovenrnmentRegulatoryAgency a
INNER JOIN (
SELECT TOP 10 p.GovernmentRegulatoryAgencyID, COUNT(p.PetID) AS NumOfPets
FROM dbo_tPet p
GROUP BY p.GovernmentRegulatoryAgencyID
ORDER BY COUNT(p.PetID) DESC
) t
ON a.GovernmentRegulatoryAgencyID = t.GovernmentRegulatoryAgencyID
In a nutshell, first get the nested query sorted, identifying what the relevant agencies are, then inner join back to the agency table to get the detail of the agencies so picked.

Need mysql query to pull data from two tables

So after helpful feedback from my original question, I now have this query:
SELECT sessions.id, sessions.title, sessions.abstract, sessions.presenters, sessions.proposal_id, proposals.outcomes, proposals.CategorySelection, proposals.research3, proposals.research4, proposals.research5, proposals.research6, proposals.innovation3, proposals.innovation4, proposals.innovation5,proposals.innovation6, proposals.application3, proposals.application4, proposals.application5, proposals.application6, proposals.integration3, proposals.integration4, proposals.integration5, proposals.integration6, proposals.references, proposals.organization
FROM sessions, proposals
INNER JOIN proposals ON proposals.id = sessions.proposal_id
WHERE sessions.id = '$id
LIMIT 1;)
that is getting me nowhere fast. What am I doing wrong?
Original question:
I need to pull several fields from one table and several more from a second table. The criteria is that a field called proposal_id match the id field of the second table. I am fairly new so this is what I have so far. It is not working, but not sure how to make it work.
(SELECT `title`,`abstract`,`presenters`,`proposal_id` FROM `sessions` WHERE `id`='$id')
UNION
(SELECT `outcomes`,`CategorySelection`,`research3`,`research4`,`research5`,`research6`,`innovation3`,`innovation4`,`innovation5`,
`innovation6`,`application3`,`application4`,`application5`,`application6`,`integration3`,`integration4`,`integration5`,`integration6`,`references`,`organization` FROM `proposals` WHERE `id`= `sessions`.`proposal_id`)
LIMIT 1;
You need to use JOIN not UNION
select
s.*,p.*
from `sessions` s
inner join `proposals` p on p.id = s.proposal_id
where s.id = '$id'
This is how you can join both the tables using the common key between.
You can select the specific fields instead of .* by specifying the column names as
s.col1,s.col2,p.col1,p.col2
etc
Try to use JOINS, where you can match the related fields from both the tables , this is the most convenient way to fetch records from multiple tables
UNION is used when you want to combine two queries
select a.id,b.some_field from table1 as a
INNER JOIN table2 as b ON b.prospal_id = a.id