Can you guys guide me as to why this does not work?
SELECT AN.an_id, AN.an_name,
(SELECT TOP(1)ex_date
FROM upd_exam_headers
WHERE HS.an_id = AN.an_id
ORDER BY ex_date desc),
sum(ex_fee)
INTO upd_nc_felines AS FS
FROM upd_animals AS AN
LEFT JOIN upd_exam_headers AS HS ON HS.an_id = AN.an_id
LEFT JOIN upd_exam_details AS DS ON DS.ex_id = HS.ex_id
WHERE an_type = 'cat' and an_status = 'NC'
GROUP BY AN.an_id, AN.an_name;
Msg 156, Level 15, State 1, Line 10
Incorrect syntax near the keyword 'AS'.
The error message says what it means :)
Add an alias to sum(ex_fee)
Give a try to this, hope should work,
WITH TMP AS (
SELECT
AN.an_id, AN.an_name,
(SELECT TOP 1 ex_date
FROM upd_exam_headers
WHERE HS.an_id = AN.an_id
ORDER BY ex_date desc) AS 'ex_date',
sum(ex_fee) AS 'ex_fee'
FROM upd_animals AS AN
LEFT JOIN upd_exam_headers AS HS ON HS.an_id = AN.an_id
LEFT JOIN upd_exam_details AS DS ON DS.ex_id = HS.ex_id
WHERE an_type = 'cat' and an_status = 'NC'
GROUP BY AN.an_id, AN.an_name;
)
SELECT * INTO
upd_nc_felines
FROM TMP
Related
I'm not sure how to make the following SQL query more efficient. Right now, the query is taking 8 - 12 seconds on a pretty fast server, but that's not close to fast enough for a Website when users are trying to load a page with this code on it. It's looking through tables with many rows, for instance the "Post" table has 717,873 rows. Basically, the query lists all Posts related to what the user is following (newest to oldest).
Is there a way to make it faster by only getting the last 20 results total based on PostTimeOrder?
Any help would be much appreciated or insight on anything that can be done to improve this situation. Thank you.
Here's the full SQL query (lots of nesting):
SELECT DISTINCT p.Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(p.PostCreationTime) AS PostTimeOrder
FROM Post p
WHERE (p.Id IN (SELECT pc.PostId
FROM PostCreator pc
WHERE (pc.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pc.UserId = '100')
))
OR (p.Id IN (SELECT pum.PostId
FROM PostUserMentions pum
WHERE (pum.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pum.UserId = '100')
))
OR (p.Id IN (SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100'))
))
OR (p.Id IN (SELECT psm.PostId
FROM PostSMentions psm
WHERE (psm.StockId IN (SELECT sf.StockId
FROM StockFollowing sf
WHERE sf.UserId = '100' ))
))
UNION ALL
SELECT DISTINCT p.Id AS Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(upe.PostEchoTime) AS PostTimeOrder
FROM Post p
INNER JOIN UserPostE upe
on p.Id = upe.PostId
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND (uf.FollowingId = '100' OR upe.UserId = '100'))
ORDER BY PostTimeOrder DESC;
Changing your p.ID in (...) predicates to existence predicates with correlated subqueries may help. Also since both halves of your union all query are pulling from the Post table and possibly returning nearly identical records you might be able to combine the two into one query by left outer joining to UserPostE and adding upe.PostID is not null as an OR condition in the WHERE clause. UserFollowing will still inner join to UPE. If you want the same Post record twice once with upe.PostEchoTime and once with p.PostCreationTime as the PostTimeOrder you'll need keep the UNION ALL
SELECT
DISTINCT -- <<=- May not be needed
p.Id
, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime
, p.Content AS Content
, p.Bu AS Bu
, p.Se AS Se
, UNIX_TIMESTAMP(coalesce( upe.PostEchoTime
, p.PostCreationTime)) AS PostTimeOrder
FROM Post p
LEFT JOIN UserPostE upe
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND
(uf.FollowingId = '100' OR
upe.UserId = '100'))
on p.Id = upe.PostId
WHERE upe.PostID is not null
or exists (SELECT 1
FROM PostCreator pc
WHERE pc.PostId = p.ID
and pc.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pc.UserID
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM PostUserMentions pum
WHERE pum.PostId = p.ID
and pum.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pum.UserId
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM SStreamPost ssp
WHERE ssp.PostId = p.ID
and exists (SELECT 1
FROM SStreamFollowing ssf
WHERE ssf.SStreamId = ssp.SStreamId
and ssf.UserId = '100')
)
OR exists (SELECT 1
FROM PostSMentions psm
WHERE psm.PostId = p.ID
and exists (SELECT
FROM StockFollowing sf
WHERE sf.StockId = psm.StockId
and sf.UserId = '100' )
)
ORDER BY PostTimeOrder DESC
The from section could alternatively be rewritten to also use an existence clause with a correlated sub query:
FROM Post p
LEFT JOIN UserPostE upe
on p.Id = upe.PostId
and ( upe.UserId = '100'
or exists (select 1
from UserFollowing uf
where uf.FollwedID = upe.UserID
and uf.FollowingId = '100'))
Turn IN ( SELECT ... ) into a JOIN .. ON ... (see below)
Turn OR into UNION (see below)
Some the tables are many:many mappings? Such as SStreamFollowing? Follow the tips in http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
Example of IN:
SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (
SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100' ))
-->
SELECT ssp.PostId
FROM SStreamPost ssp
JOIN SStreamFollowing ssf ON ssp.SStreamId = ssf.SStreamId
WHERE ssf.UserId = '100'
The big WHERE with all the INs becomes something like
JOIN ( ( SELECT pc.PostId AS id ... )
UNION ( SELECT pum.PostId ... )
UNION ( SELECT ssp.PostId ... )
UNION ( SELECT psm.PostId ... ) )
Get what you can done of that those suggestions, then come back for more advice if you still need it. And bring SHOW CREATE TABLE with you.
When I execute this query, it works fine:
SELECT
pr.pr_nombre , cl.cl_nomcorto,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951 as Interes,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049 as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
ORDER BY pr.pr_nombre
I get this:
Query results
Now I need to show it adding columns "Interes" and "WH" on records with same "Agrupador", something like this:
SELECT
pr.pr_nombre , cl.cl_nomcorto,
sum(mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951) as Interes,
sum(mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049) as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
GROUP BY pr.pr_nombre , cl.cl_nomcorto, (select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null)
ORDER BY pr.pr_nombre
And I get this error message:
Msg 144, Level 15, State 1, Line 12
Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause.
Any help will be welcome.
Can you make use of CTE here?
;WITH CTE as
(
SELECT
pr.pr_nombre , cl.cl_nomcorto,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951 as Interes,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049 as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
ORDER BY pr.pr_nombre
)
select pr_nombre,cl_nomcorto,sum(Interes),sum(WH),Agrupador
from CTE
group by pr_nombre,cl_nomcorto,Agrupador
order by pr_nombre
I'm currently stuck here and don't know what to do next since I can't use the tv_main alias into the 2 level deep subquery. Here's my code (I commented the part that have a problem). Any help will be appreciated. Thanks.
SELECT tv_main.id,
tv_main.vesselName,
(
SELECT SUM(t_statCtr.status = 'EX CREW')
FROM
(
(
SELECT tpi_stat.id,
tvv.vesselName,
lastname,
firstname,
middlename,
IF(tpi_stat.returningCrew = 1, 'NEW HIRE',
IF(COUNT(tc_ctr.personnel_id) > 1, 'EX CREW', 'NEW HIRE')
)
AS status
FROM tbl_contracts AS tc_stat
LEFT JOIN tbl_personnel_info AS tpi_stat
ON tpi_stat.id = tc_stat.personnel_id
LEFT JOIN tbl_contracts AS tc_ctr
ON tpi_stat.id = tc_ctr.personnel_id
LEFT JOIN tbl_vessels AS tvv
ON tvv.id = tpi_stat.lastJoinedVsl
WHERE
tpi_stat.emp_status = 'ON-BOARD'
AND tc_stat.status = 'ACTIVE'
AND tvv.id = tv_main.id --This line have an error, (Unknown Column tv_main.id in where clause)
GROUP BY tc_stat.personnel_id
) AS t_statCtr
)
) AS ex_crew,
NULL AS new_hire
FROM tbl_vessels AS tv_main -- I need this one to use inside the subquery
LEFT JOIN tbl_personnel_info AS tpi
ON tv_main.id = tpi.lastJoinedVsl
LEFT JOIN tbl_contracts AS tc
ON tpi.id = tc.personnel_id
WHERE
tpi_stat.emp_status = 'ON-BOARD'
AND tc_stat.status = 'ACTIVE'
GROUP BY tv_main.vesselName
I finally solve it. I didn't know that mysql only allow correlation of 1 deep level.
SELECT tv_main.vesselName,
SUM(t_dummy.statusx = 'EX CREW') AS ex_crew,
SUM(t_dummy.statusx = 'NEW HIRE') AS new_hire
FROM tbl_vessels AS tv_main
LEFT JOIN tbl_personnel_info AS tpi_main
ON tpi_main.lastJoinedVsl = tv_main.id
LEFT JOIN tbl_contracts AS tc_main
ON tc_main.personnel_id = tpi_main.id
LEFT JOIN
(
SELECT tvv.id,
tpi_stat.id AS tpiid,
IF(tpi_stat.returningCrew = 1, 'NEW HIRE',
IF(COUNT(tc_ctr.personnel_id) > 1, 'EX CREW', 'NEW HIRE')
)
AS statusx
FROM tbl_contracts AS tc_stat
LEFT JOIN tbl_personnel_info AS tpi_stat
ON tpi_stat.id = tc_stat.personnel_id
LEFT JOIN tbl_contracts AS tc_ctr
ON tpi_stat.id = tc_ctr.personnel_id
LEFT JOIN tbl_vessels AS tvv
ON tvv.id = tpi_stat.lastJoinedVsl
GROUP BY tc_stat.personnel_id
) AS t_dummy
ON tpi_main.id = t_dummy.tpiid
WHERE
tpi_main.emp_status = 'ON-BOARD'
AND tc_main.status = 'ACTIVE'
AND t_dummy.id = tv_main.id
GROUP BY tv_main.vesselName;
I have this below:
SELECT a.* FROM ( SELECT
asset_liability_income_expenditure_tbl.a_l_code,
SUM(mainaccount_a_2017.amount), mainaccount_a_2017.dr_cr_action
FROM `mainaccount_a_2017` LEFT JOIN chart_of_account
ON (
chart_of_account.joint_account_numbers =
mainaccount_a_2017.joint_account_number
)
LEFT JOIN asset_liability_income_expenditure_tbl
ON (
asset_liability_income_expenditure_tbl.a_l_code =
chart_of_account.account_type
)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_a_2017.dr_cr_action = 'DR' UNION
SELECT asset_liability_income_expenditure_tbl.a_l_code,
SUM(mainaccount_b_2017.amount),
mainaccount_b_2017.dr_cr_action
FROM `mainaccount_b_2017`
LEFT JOIN chart_of_account ON (
chart_of_account.joint_account_numbers =
mainaccount_b_2017.joint_account_number
)
LEFT JOIN asset_liability_income_expenditure_tbl ON (
asset_liability_income_expenditure_tbl.a_l_code =
chart_of_account.account_type
)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_b_2017.dr_cr_action = 'DR'
) AS a
it works fine, but displays either one empty row at the top and the sum below or vis-a-vis. I tried LIMIT 1, but the problem is when the SUM(amount) outputs in row 2, i cannot fetch and if I don't apply any limit, it only fetches result whose SUM(amount) outputs in row 1. I don't know what am missing. Please kindly assist. Thanks.
I figured it out. I had to flip something. Results below:
SELECT SUM(a) FROM
(
SELECT SUM(mainaccount_a_2017.amount)
AS a FROM `mainaccount_a_2017`
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_a_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_a_2017.dr_cr_action = 'DR'
UNION ALL
SELECT SUM(mainaccount_b_2017.amount)
AS a FROM `mainaccount_b_2017`
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_b_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA' AND mainaccount_b_2017.dr_cr_action = 'DR'
) a
SELECT
E.`employee_id`,
E.`full_name`,
LE.`no_of_leaves` AS AllocatedLeaves,
MLLT.`leave_type` AS LeaveTypeName,
COUNT(SELECT * FROM leave_approval WHERE employee_id = 1) AS TotalLeavesTaken
FROM employee E
INNER JOIN leave_entitlement LE
ON E.`employee_id` = LE.`employee_id`
INNER JOIN `ml_leave_type` MLLT
ON MLLT.`ml_leave_type_id` = LE.`ml_leave_type_id`
LEFT JOIN leave_approval LA
ON E.`employee_id` = LA.`employee_id`
LEFT JOIN leave_application LAPP
ON LAPP.`application_id` = LA.`leave_application_id`
LEFT JOIN ml_leave_type MLLTLA
ON MLLTLA.`ml_leave_type_id` = LAPP.`ml_leave_type_id`
i am getting syntax error near count, but i tried to find out the syntax error and i could not find any?
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select * from leave_approval where employee_id = 1) AS TotalLeavesTaken
from emp' at line 6
Is it really a syntax error. or is there something i am missing here??
This line:
COUNT(SELECT * FROM leave_approval WHERE employee_id = 1) AS TotalLeavesTaken
is incorrect. You can not do a count on select * subquery without placing it in parentheses, but even then you'd need a group by and additional logic. The better approach would be:
(Select count(*) from leave_approval where employee_id = 1) AS TotalLeavesTaken
change
COUNT(SELECT * FROM leave_approval WHERE employee_id = 1) AS TotalLeavesTaken
to
(SELECT count(*) FROM leave_approval WHERE employee_id = 1) AS TotalLeavesTaken
No need to use subquery for count in your case check below query
Try this:
SELECT E.employee_id, E.full_name, LE.no_of_leaves AS AllocatedLeaves,
MLLT.leave_type AS LeaveTypeName,
SUM(CASE WHEN LA.employee_id = 1 THEN 1 ELSE 0 END) AS TotalLeavesTakenByEmplyeeNo1
FROM employee E
INNER JOIN leave_entitlement LE ON E.employee_id = LE.employee_id
INNER JOIN `ml_leave_type` MLLT ON MLLT.ml_leave_type_id = LE.ml_leave_type_id
LEFT JOIN leave_approval LA ON E.employee_id = LA.employee_id
LEFT JOIN leave_application LAPP ON LAPP.application_id = LA.leave_application_id
LEFT JOIN ml_leave_type MLLTLA ON MLLTLA.ml_leave_type_id = LAPP.ml_leave_type_id
GROUP BY E.employee_id;
Try This Query
SELECT E.`employee_id`,E.`full_name`,LE.`no_of_leaves` AS AllocatedLeaves,MLLT.`leave_type` AS LeaveTypeName,
SUM( CASE WHEN LA.employee_id = '1' THEN 1 ELSE 0 END ) as TotalLeavesTaken
FROM employee E
INNER JOIN leave_entitlement LE
ON E.`employee_id` = LE.`employee_id`
INNER JOIN `ml_leave_type` MLLT
ON MLLT.`ml_leave_type_id` = LE.`ml_leave_type_id`
LEFT JOIN leave_approval LA
ON E.`employee_id` = LA.`employee_id`
LEFT JOIN leave_application LAPP
ON LAPP.`application_id` = LA.`leave_application_id`
LEFT JOIN ml_leave_type MLLTLA
ON MLLTLA.`ml_leave_type_id` = LAPP.`ml_leave_type_id`
Only you have to replace COUNT(SELECT * FROM leave_approval WHERE employee_id = 1) to SUM( CASE WHEN LA.employee_id = '1' THEN 1 ELSE 0 END )
Thanks it, Try this because i have tried this query and it will give you perfect result