SQL help on subqueries and table joins - mysql

Need some sql help...using MYSQL...I've got some legacy code and a situation to resolve...This code below only returns occupants who have a record in the p_occupants_insurance table. I want to be able to list all the occupants regardless if they have a record in the p_occupants_insurance table or not.
SELECT a.occupants_insurance_id, a.occupant_id, a.policy_nbr, a.policy_type, a.coverage_amount_curr,
CASE
WHEN a.effective_date = '0000-00-00' THEN NULL
ELSE a.effective_date
END as effective_date,
CASE
WHEN a.expiration_date = '0000-00-00' THEN NULL
ELSE a.expiration_date
END as expiration_date,
a.insurance_company, a.custom1_label, a.custom2_label, a.custom3_label, a.custom1, a.custom2, a.custom3, c.name as prop_name, (SELECT x.name FROM portfolio_hierarchy x WHERE x.leaf_node_portf_id = d.portfolio_id ) as p_name, b.name as occupant_name, b.primary_contact, b.phone
FROM p_occupants_insurance a, p_occupants b, properties c, portfolio d
WHERE a.occupant_id = b.occupant_id
AND b.property_id = c.properties_id
AND c.portfolio_id = d.portfolio_id
AND d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC, prop_name ASC, occupant_name ASC, insurance_company ASC, policy_nbr ASC;
I know I can do subqueries like this:
SELECT b.name as occupant_name, b.primary_contact, b.phone,
(SELECT a.occupants_insurance_id FROM p_occupants_insurance a WHERE a.occupants_id = b.occupants_id) as occupants_insurance_id
FROM p_occupants b, properties c, portfolio d
WHERE a.occupant_id = b.occupant_id
AND b.property_id = c.properties_id
AND c.portfolio_id = d.portfolio_id
AND d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC, prop_name ASC, occupant_name ASC, insurance_company ASC, policy_nbr ASC;
But that is going to lead to a subquery for each column I want out of the p_occupants_insurance table. Is there a better way to accomplish this and can you help me write out the SQL? Sorry, SQL is not my strongest point.
Thanks for the help.

Without seeing the schema for each of the tables involved, and relying only on the sample SQL statement, it is difficult to say for sure, but I believe the following will return the result you are looking for:
SELECT
a.`occupants_insurance_id`,
a.`occupant_id`,
a.`policy_nbr`,
a.`policy_type`,
a.`coverage_amount_curr`,
IF(a.`effective_date` = '0000-00-00',NULL,a.`effective_date`) as a.`effective_date`,
IF(a.`expiration_date` = '0000-00-00',NULL,a.`expiration_date`) as a.`expiration_date`,
a.`insurance_company`,
a.`custom1_label`,
a.`custom2_label`,
a.`custom3_label`,
a.`custom1`,
a.`custom2`,
a.`custom3`,
c.`name` as `prop_name`,
(SELECT x.name FROM portfolio_hierarchy x WHERE x.leaf_node_portf_id = d.portfolio_id ) as `p_name`,
b.`name` as `occupant_name`,
b.`primary_contact`,
b.`phone`
FROM `p_occupants` b
LEFT JOIN `p_occupants_insurance` a
ON a.`occupant_id` = b.`occupant_id`
JOIN `properties` c
ON b.`property_id` = c.`properties_id`
JOIN `portfolio` d
ON c.`portfolio_id` = d.`portfolio_id`
WHERE d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC,
`prop_name` ASC,
`occupant_name` ASC,
`insurance_company` ASC,
`policy_nbr` ASC;

Related

MySQL query taking too much time

query taking 1 minute to fetch results
SELECT
`jp`.`id`,
`jp`.`title` AS game_title,
`jp`.`game_type`,
`jp`.`state_abb` AS game_state,
`jp`.`location` AS game_city,
`jp`.`zipcode` AS game_zipcode,
`jp`.`modified_on`,
`jp`.`posted_on`,
`jp`.`game_referal_amount`,
`jp`.`games_referal_amount_type`,
`jp`.`status`,
`jp`.`is_flaged`,
`u`.`id` AS employer_id,
`u`.`email` AS employer_email,
`u`.`name` AS employer_name,
`jf`.`name` AS game_function,
`jp`.`game_freeze_status`,
`jp`.`game_statistics`,
`jp`.`ats_value`,
`jp`.`integration_id`,
`u`.`account_manager_id`,
`jp`.`model_game`,
`jp`.`group_id`,
(CASE
WHEN jp.group_id != '0' THEN gm.group_name
ELSE 'NA'
END) AS group_name,
`jp`.`priority_game`,
(CASE
WHEN jp.country != 'US' THEN jp.country_name
ELSE ''
END) AS game_country,
IFNULL((CASE
WHEN
`jp`.`account_manager_id` IS NULL
OR `jp`.`account_manager_id` = 0
THEN
(SELECT
(CASE
WHEN
account_manager_id IS NULL
OR account_manager_id = 0
THEN
`u`.`account_manager_id`
ELSE account_manager_id
END) AS account_manager_id
FROM
user_user
WHERE
id = (SELECT
user_id
FROM
game_user_assigned
WHERE
game_id = `jp`.`id`
LIMIT 1))
ELSE `jp`.`account_manager_id`
END),
`u`.`account_manager_id`) AS acc,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '1'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS somewhatgame,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '2'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS verygamecommitted,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '3'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS notgame,
(SELECT
COUNT(joa.id) AS applicationcount
FROM
game_refer_to_member jrmm
INNER JOIN
game_refer jrr ON jrr.id = jrmm.rid
INNER JOIN
game_applied joa ON jrmm.id = joa.referred_by
WHERE
jrmm.STATUS = '1'
AND jrr.referby_user_id IN (SELECT
ab_testing_user_id
FROM
ab_testing)
AND joa.game_post_id = rpr.recach_limit_game_id
AND (rpr.recach_limit = 1
OR rpr.recach_limit = 2)) AS gamecount
FROM
(`game_post` AS jp)
JOIN
`user_info` AS u ON `jp`.`user_user_id` = `u`.`id`
JOIN
`game_functional` jf ON `jp`.`game_functional_id` = `jf`.`id`
LEFT JOIN
`group_musesm` gm ON `gm`.`group_id` = `jp`.`group_id`
LEFT JOIN
`recach_limit` rpr ON `jp`.`id` = `rpr`.`recach_limit_game_id`
WHERE
`jp`.`status` != '3'
GROUP BY `jp`.`id`
ORDER BY `posted_on` DESC
LIMIT 10
I would first suggest not nesting select statements because this will cause an n^x performance hit on every xth level and I see at least 3 levels of selects inside this query.
Add index
INDEX(status, posted_on)
Move LIMIT inside
Then, instead of saying
FROM (`game_post` AS jp)
say
FROM ( SELECT id FROM game_post
WHERE status != 3
ORDER BY posted_on DESC
LIMIT 10 ) AS ids
JOIN game_post AS jp USING(id)
(I am assuming that the PK of jp is (id)?)
That should efficiently use the new index to get the 10 ids needed. Then it will reach back into game_post to get the other columns.
LEFT
Also, don't say LEFT unless you need it. It costs something to generate NULLs that you may not be needing.
Is GROUP BY necessary?
If you remove the GROUP BY, does it show dup ids? The above changes may have eliminated the need.
IN(SELECT) may optimize poorly
Change
AND jrr.referby_user_id IN ( SELECT ab_testing_user_id
FROM ab_testing )
to
AND EXISTS ( SELECT * FROM ab_testing
WHERE ab_testing_user_id = jrr.referby_user_id )
(This change may or may not help, depending on the version you are running.)
More
Please provide EXPLAIN SELECT if you need further assistance.

Update an existing table using selected records in tsql

I am stuck with a query where I need to update an existing table using a dynamically generated record set. I tried searching for the answers but didn't get much help from them.
Here is my query:
with t as
(
SELECT R.Col1, R.Col2, O.Column2, row_number()
OVER (partition by R.Col3, R.Col4
ORDER BY
CASE WHEN #Criteria = 'NA' then R.Col1 END ASC,
CASE WHEN #Criteria = 'ND' then R.Col1 END DESC,
CASE WHEN #Criteria = 'CA' then R.Col2 END ASC,
CASE WHEN #Criteria = 'CD' then R.Col1 END DESC
) as NewOrder
From RecordsTable R innerjoin OtherTable O on R.Col2 = O.Column1
where R.Col3 = #Col5Val
)
Update RecordsTable Set RecordsTable.Ordering = t.NewOrder
where RecordsTable.Name = t.Col1
and RecordsTable.Address = t.Col2
The error I am getting is The multi-part identifier "t.Col1" could not be bound and The multi-part identifier "t.Col2" could not be bound
I am not sure if the query is correct or not, but I guess this should be correct to some extent.
Table Structures
RecordsTable
Col1 | Col2 | Col3 | Col4 | Ordering
------------------------------------------------------------
ABC | 78945 | 8345 | XYZ | 1
OtherTable
Column1 | Column2 | Column3
-----------------------------------
FOO | BAR | 8345
NOTE
The cases are required to sort the records as the NewOrder generated from this is required to update the RecordsTable
You are updating one of the tables involved in your CTE, but you aren't linking it to the CTE during your update. Therefore, you need to join the source table back to the CTE using an inner join in your update statement like so:
--CTE here
Update RecordsTable
Set RecordsTable.Ordering = t.NewOrder
from recordstable r
inner join t on
r.Name = t.Col1 and r.Address = t.Col2
Alternatively, you can include the Name, Address and Ordering columns in your CTE, and directly update the CTE like so:
with t as
(
SELECT R.Col1, R.Col2, O.Column2, R.Name, R.Address, R.Ordering, row_number()
OVER (partition by R.Col3, R.Col4
ORDER BY
CASE WHEN #Criteria = 'NA' then R.Col1 END ASC,
CASE WHEN #Criteria = 'ND' then R.Col1 END DESC,
CASE WHEN #Criteria = 'CA' then R.Col2 END ASC,
CASE WHEN #Criteria = 'CD' then R.Col1 END DESC
) as NewOrder
From RecordsTable R innerjoin OtherTable O on R.Col2 = O.Column1
where R.Col3 = #Col5Val
)
Update t
Set t.Ordering = t.NewOrder
where t.Name = t.Col1
and t.Address = t.Col2
Demo

Join between sub-queries in SQLAlchemy

In relation to the answer I accepted for this post, SQL Group By and Limit issue, I need to figure out how to create that query using SQLAlchemy. For reference, the query I need to run is:
SELECT t.id, t.creation_time, c.id, c.creation_time
FROM (SELECT id, creation_time
FROM thread
ORDER BY creation_time DESC
LIMIT 5
) t
LEFT OUTER JOIN comment c ON c.thread_id = t.id
WHERE 3 >= (SELECT COUNT(1)
FROM comment c2
WHERE c.thread_id = c2.thread_id
AND c.creation_time <= c2.creation_time
)
I have the first half of the query, but I am struggling with the syntax for the WHERE clause and how to combine it with the JOIN. Any one have any suggestions?
Thanks!
EDIT: First attempt seems to mess up around the .filter() call:
c = aliased(Comment)
c2 = aliased(Comment)
subq = db.session.query(Thread.id).filter_by(topic_id=122098).order_by(Thread.creation_time.desc()).limit(2).offset(2).subquery('t')
subq2 = db.session.query(func.count(1).label("count")).filter(c.id==c2.id).subquery('z')
q = db.session.query(subq.c.id, c.id).outerjoin(c, c.thread_id==subq.c.id).filter(3 >= subq2.c.count)
this generates the following SQL:
SELECT t.id AS t_id, comment_1.id AS comment_1_id
FROM (SELECT count(1) AS count
FROM comment AS comment_1, comment AS comment_2
WHERE comment_1.id = comment_2.id) AS z, (SELECT thread.id AS id
FROM thread
WHERE thread.topic_id = :topic_id ORDER BY thread.creation_time DESC
LIMIT 2 OFFSET 2) AS t LEFT OUTER JOIN comment AS comment_1 ON comment_1.thread_id = t.id
WHERE z.count <= 3
Notice the sub-query ordering is incorrect, and subq2 somehow is selecting from comment twice. Manually fixing that gives the right results, I am just unsure of how to get SQLAlchemy to get it right.
Try this:
c = db.aliased(Comment, name='c')
c2 = db.aliased(Comment, name='c2')
sq = (db.session
.query(Thread.id, Thread.creation_time)
.order_by(Thread.creation_time.desc())
.limit(5)
).subquery(name='t')
sq2 = (
db.session.query(db.func.count(1))
.select_from(c2)
.filter(c.thread_id == c2.thread_id)
.filter(c.creation_time <= c2.creation_time)
.correlate(c)
.as_scalar()
)
q = (db.session
.query(
sq.c.id, sq.c.creation_time,
c.id, c.creation_time,
)
.outerjoin(c, c.thread_id == sq.c.id)
.filter(3 >= sq2)
)

MySQL QUERY runs on localhost, but does not on server

I have this QUERY:
select
a.*
from
mt_proyecto a,
mt_mockup b,
mt_diseno c,
mt_modulo d
where
a.estado = 'A' and
(
(b.encargado = '1' and b.idproyecto = a.idmtproyecto) or
(c.encargado = '1' and c.idproyecto = a.idmtproyecto) or
(d.encargado = '1' and d.idproyecto = a.idmtproyecto)
)
group by
a.idmtproyecto
order by a.finalizado asc, a.feccrea desc
Result:
Then, I run the same code on server with the same database:
Is there any problem with the query?
It seems that the query is running correctly on your server, and returning no rows. Please make sure you have the same table contents on your local machine and your server.
Other things:
Pro tip: never use SELECT * or SELECT table.* in software. Always enumerate the columns you want in your result set.
Unless you use GROUP BY with aggregate functions like SUM() or `COUNT(), and naming the correct columns from the result set, it returns unpredictable results. Read this. http://dev.mysql.com/doc/refman/5.1/en/group-by-extensions.html
I solved with this QUERY:
select
a.*
from
(
mt_proyecto a
left join mt_mockup b on
b.idproyecto = a.idmtproyecto
left join mt_diseno c on
c.idproyecto = a.idmtproyecto
left join mt_modulo d on
d.idproyecto = a.idmtproyecto
left join mt_integracion e on
e.idproyecto = a.idmtproyecto
left join mt_pruebas_internas f on
f.idproyecto = a.idmtproyecto
)
where
a.estado = 'A' and
(
(a.idmtproyecto = b.idproyecto and
b.encargado = '1' ) or
(a.idmtproyecto = c.idproyecto and
c.encargado = '1' ) or
(a.idmtproyecto = d.idproyecto and
d.encargado = '1' ) or
(a.idmtproyecto = e.idproyecto and
e.encargado = '1' ) or
(a.idmtproyecto = f.idproyecto =
f.encargado = '1' )
)
group by a.idmtproyecto
order by
a.finalizado asc, a.feccrea desc
Thanks everyone for answer me. I'll do your suggestions .

Difficult MySQL Statement

I've got this query but the result is wrong.
How can I use the min() statement and the Group by Statement so that I will get for each AthletenID the lowest DiszOrder?
Select
ar_Leistungen.`AthletenID`,
ar_Leistungen.`Leistung`,
ar_Leistungen.`Disziplin`,
ar_Leistungen.`Klasse`,
min(ar_Leistungen.`DiszOrder`),
ar_Athleten.`Vorname`,
ar_Athleten.`Jahrgang`,
ar_Wettkampf.`Wettkampfdatum`
from
ar_Leistungen,
ar_Athleten,
ar_Wettkampf
Where
ar_Athleten.ID = ar_Leistungen.AthletenID and
ar_Leistungen.WettkampfID = ar_Wettkampf.ID and
ar_Leistungen.`Disziplin` = '100' and
ar_Leistungen.`Leistung` > 0 and
(ar_Athleten.`Jahrgang` = '1995' or ar_Athleten.`Jahrgang` = '1994') and
ar_Wettkampf.`Wettkampfdatum` LIKE '%2013%'
Group By
AthletenID
Order by
DiszOrder Desc
Limit
0, 100
You can have a subquery which separately gets the lowest DiszOrder for each AthletenID and join it with the other table so you can freely get the other value of the columns.
SELECT a.AthletenID,
a.Leistung,
a.Disziplin,
ar_Leistungen.Klasse,
a.DiszOrder),
b.Vorname,
b.Jahrgang,
c.Wettkampfdatum
FROM ar_Leistungen a
INNER JOIN ar_Athleten b
ON b.ID = a.AthletenID
INNER JOIN ar_Wettkampf c
ON a.WettkampfID = c.ID
INNER JOIN
(
SELECT AthletenID, MIN(DiszOrder) DiszOrder
FROM ar_Leistungen
GROUP BY AthletenID
) d ON a.AthletenID = d.AthletenID AND
a.DiszOrder = d.DiszOrder
WHERE a.Disziplin = '100' AND
a.Leistung > 0 AND
(b.Jahrgang IN ('1995', '1994'))