getting fieldname from multiple tables depending on condition - mysql

I have the following mysql query:
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
g.ForeName AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u,
tblguardian g,
tblstudent s,
tblclass c
WHERE u.UserCode = g.GuardianCode
AND u.StudentCode = s.STUDENTCODE
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
AND u.RecordStatus = 'N'
AND c.classcode = s.classcode
ORDER BY u.datetime DESC
Result of this query is shown below:
Now in my tblupdates for year-2013 and month-09 i have the following rows:
Now in my above result i am getting data for id=138 but i want to display all.The reason for not displaying other rows is that (usercode-30000,admin) these occur in tblteacher rather than tblguardian.So now i want that if the usercode is from tblguardian it shows guardian name but if it is from tblteacher it shows teachername but shows all the rows.Tblteacher and tblupdates can be joined by teachercode and usercode respectively.
I tried the following query but it doesnot return any row:
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
IF(
u.usercode NOT IN (g.guardiancode),
t.teachername,
g.ForeName
) AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u,
tblguardian g,
tblstudent s,
tblclass c,
tblteacher t
WHERE u.UserCode = g.GuardianCode
AND u.StudentCode = s.STUDENTCODE
AND t.teachercode = u.usercode
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
AND u.RecordStatus = 'N'
AND c.classcode = s.classcode
ORDER BY u.datetime DESC
Please help me out

Try this with using CASE and i have joined you tables using LEFT join so there can be duplicates i have use GROUP BY also by u.id but bit confused for right column name please put the right column in group by
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
(CASE
WHEN u.usercode = t.teachercode THEN t.teachername
WHEN u.usercode = g.guardiancode THEN g.ForeName
ELSE END ) AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u
LEFT JOIN tblguardian g ON (u.UserCode = g.GuardianCode )
LEFT JOIN tblstudent s ON (u.StudentCode = s.STUDENTCODE )
LEFT JOIN tblclass c ON (c.classcode = s.classcode )
LEFT JOIN tblteacher t ON (t.teachercode = u.usercode)
WHERE u.RecordStatus = 'N'
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
GROUP BY u.id
ORDER BY u.datetime DESC

Related

How to return a 0 using count instead of empty response?

I have this query that is inside another one that calculates avg per month, but when this query doesn't return anything, then I have an empty table as a result, but I want it to be a 0 instead, I think this result is because of the group by
select
coalesce(count(distinct t.order_id),0) as ordenes,
'Erradas' as tipo,
EXTRACT(MONTH FROM o.order_creation_date) as mes
from (
select
orders.order_id,
pd.missing ,
pd.incomplete ,
pd.damaged,
pd.status_code ,
r.reason ,
r.reason_type,
(case
when ((pd.missing is null) and (pd.incomplete is null) and (pd.damaged is null))
then NULL
when ((r.reason_type not in ('F', 'W')) and
(((pd.missing + pd.incomplete) + pd.damaged) > 0)) then 1
when ((r.reason = 'F') and (pd.missing > 0)) then 1
when ((r.reason = 'W') and (pd.missing > 0)) then 0
else 0 end) AS refund_result
from module.orders
inner join module.pack p on orders.order_id = p.order_id
inner join module.pack_d pd on p.asn = pd.asn
left join module.reason r on r.reason = p.reason
INNER JOIN module.mv_reporte mc ON orders.customer_id = mc.rut
WHERE mc.level = 'VIP'
) t
inner join ecommerce.orders o on o.order_no = t.id
where refund_result = 1
and o.order_creation_date BETWEEN '2022/01/01' AND '2022/12/31'
group by month
order by month
As you can see, I tried to use coalesce, but it didn't work

Parentheses in mysql query giving different results

I have a query that is giving me different results when i enclosed it in Parentheses, however when I run it without Parentheses its giving me different results. I want to apply Union in between so I have to use Parentheses as without union doesn't work.
The query is as follows:
SELECT Distinct
recurring_billing.id,
recurring_billing.kid_id,
recurring_billing.class_id,
recurring_billing.app_id,
recurring_billing.Region_ID,
CC.month_name,
CC.billing_year,
CASE
WHEN
CC.month_name = recurring_billing.billing_month
AND CC.billing_year = recurring_billing.billing_year
THEN
recurring_billing.billing_status
ELSE
'Pending'
END
AS billing_status, tblkids.kid_name, tblkids.kid_Lastname, tblkids.kid_EMail, tbl_app.app_CCExp AS cc_exp, tbl_app.app_CCName AS cc_name, tbl_app.app_CCNumber AS cc_number, tbl_app.app_CCType AS cc_type, tblclasses.cla_EndDate, tblclassdays.classday_day, CC.remainingclasses, tbl_app.cost_per_class, CC.remainingclasses * tbl_app.cost_per_class AS cost_amount,
CASE
WHEN
OP.override_amt IS NOT NULL
THEN
OP.override_amt
ELSE
CC.remainingclasses * tbl_app.cost_per_class
END
AS pmt_amount,
CASE
WHEN
OP.process_payment = False
THEN
OP.process_payment
ELSE
True
END
AS process_payment
FROM
recurring_billing
LEFT JOIN
tblkidsxclass
ON recurring_billing.kid_id = tblkidsxclass.kxc_kidid
AND recurring_billing.app_id = tblkidsxclass.kxc_appid
LEFT JOIN
tbl_app
ON recurring_billing.app_ID = tbl_app.app_ID
LEFT JOIN
tblkids
ON recurring_billing.kid_id = tblkids.kid_ID
LEFT JOIN
tblclasses
ON recurring_billing.class_id = tblclasses.cla_ID
LEFT JOIN
tblclassdays
ON tblclasses.cla_ID = tblclassdays.classday_classID
INNER JOIN
(
SELECT
MONTHNAME(classday_day) AS month_name,
YEAR(classday_day) AS billing_year,
cla_ID,
COUNT(classday_classid) AS remainingclasses,
c.cost_per_class AS cost_per_class,
COUNT(classday_classid) * cost_per_class AS TotalClassCost
FROM
tblclassdays
JOIN
(
SELECT
tblclasses.cla_ID,
tblclasses.cost_per_class,
tblclasses.cla_nextclass AS next1,
tblclasses_1.cla_nextclass AS next2
FROM
tblclasses
LEFT JOIN
tblclasses AS tblclasses_1
ON tblclasses.cla_nextclass = tblclasses_1.cla_ID
WHERE
tblclasses.cla_ID IN
(
SELECT DISTINCT
recurring_billing.class_id
FROM
recurring_billing
LEFT JOIN
tblkidsxclass
ON recurring_billing.kid_id = tblkidsxclass.kxc_kidid
AND recurring_billing.app_id = tblkidsxclass.kxc_appid -- LEFT JOIN tblkids ON recurring_billing.kid_id = tblkids.kid_ID
LEFT JOIN
tblclasses
ON recurring_billing.class_id = tblclasses.cla_ID -- LEFT JOIN tblclassdays ON tblclasses.cla_ID = tblclassdays.classday_classID
WHERE
ISNULL(tblkidsxclass.kxc_dropoutdate)
AND tblkidsxclass.pmt_option = 'Recurring'
AND tblclasses.cla_active = TRUE -- AND tblclasses.cla_EndDate >= NOW()
GROUP BY
recurring_billing.id
)
)
c
ON tblclassdays.classday_classid IN
(
c.cla_ID,
c.next1,
c.next2
)
WHERE
tblclassdays.classday_noclass = FALSE
AND MONTH(classday_day) = 11
AND YEAR(classday_day) = 2020
AND
(
CONCAT(CAST(classday_day AS DATE), ' ', CAST(classday_endtime AS TIME)) > CAST(CURDATE() AS DATETIME)
)
GROUP BY
cla_ID
)
CC
ON CC.cla_ID = tblclassdays.classday_classID
LEFT JOIN
override_payments OP
ON recurring_billing.app_id = OP.app_id
AND recurring_billing.kid_id = OP.kid_id
AND CC.month_name = OP.billing_month
AND CC.billing_year = OP.billing_year
WHERE
ISNULL(tblkidsxclass.kxc_dropoutdate)
AND tblkidsxclass.pmt_option = 'Recurring'
AND tblclasses.cla_active = TRUE
AND recurring_billing.kid_id NOT IN
(
SELECT
kid_id
from
recurring_billing
where
billing_month = 'November'
and billing_year = '2020'
)
-- AND tblclasses.cla_EndDate >= NOW()
GROUP BY
recurring_billing.id
ORDER BY
recurring_billing.id ASC
Same query if enclosed in Parentheses will give me different results.
Parentheses are not required for a UNION statement. The following 2 union statements both work and yield the same results.
SELECT 1 UNION SELECT 2;
(SELECT 1) UNION (SELECT 2);

Joining 2 SQL queries into 1 result

I have two SQL queries that I would like to join into one:
select d.full_month, COUNT(*) amount
from fact_ticket t
join dim_queue q on t.queue_id = q.queue_id
join vt_scopes s on t.scope_id = s.scope_id
join dim_date d on t.create_date_id = d.date_id
where q.name = 'Support'
and year(GETDATE()) = YEAR(t.create_date)
and s.statusname not in ('discarded', 'closed')
group by d.full_month
order by 1;
and
select d.full_month, COUNT(*) amount
from fact_ticket t
join dim_queue q on t.queue_id = q.queue_id
join vt_scopes s on t.scope_id = s.scope_id
join dim_date d on t.create_date_id = d.date_id
where q.name = 'Support'
and year(GETDATE()) = YEAR(t.create_date)
and s.statusname in ('closed')
group by d.full_month
order by 1;
Both gives me now a result with a date column and an amount column, but I would like to get everything in one query where I would get date, amount 1, amount 2.
Is there an easy to do this?
You can use below query-
SELECT d.full_month,
COUNT(IF(s.statusname NOT IN ('discarded', 'closed'),1,NULL)) amount1,
COUNT(IF(s.statusname IN ('closed'),1,NULL)) amount2
FROM fact_ticket t
JOIN dim_queue q ON t.queue_id = q.queue_id
JOIN vt_scopes s ON t.scope_id = s.scope_id
JOIN dim_date d ON t.create_date_id = d.date_id
WHERE q.name = 'Support'
AND YEAR(GETDATE()) = YEAR(t.create_date)
GROUP BY d.full_month
ORDER BY 1;
2nd Edition: Even you can get benefit of index if exist on create_date by below query-
SELECT d.full_month,
COUNT(IF(s.statusname NOT IN ('discarded', 'closed'),1,NULL)) amount1,
COUNT(IF(s.statusname IN ('closed'),1,NULL)) amount2
FROM fact_ticket t
JOIN dim_queue q ON t.queue_id = q.queue_id
JOIN vt_scopes s ON t.scope_id = s.scope_id
JOIN dim_date d ON t.create_date_id = d.date_id
WHERE q.name = 'Support'
AND t.create_date>= DATE_FORMAT(NOW(),'%Y-01-01 00:00:00') AND t.create_date <= DATE_FORMAT(NOW(),'%Y-12-31 23:59:59');
GROUP BY d.full_month
ORDER BY 1;
Another way using sum function
SELECT
d.full_month,
SUM(s.statusname NOT IN ('discarded', 'closed')) amount,
SUM(s.statusname = 'closed') amount_closed
FROM
fact_ticket t
JOIN dim_queue q
ON t.queue_id = q.queue_id
JOIN vt_scopes s
ON t.scope_id = s.scope_id
JOIN dim_date d
ON t.create_date_id = d.date_id
WHERE q.name = 'Support'
AND YEAR(GETDATE ()) = YEAR(t.create_date)
GROUP BY d.full_month
ORDER BY 1 ;

MySQL search query with multiple joins and subqueries running slow

I have the following query which is actually within a stored procedure, but I removed it as there is too much going on inside the stored procedure. Basically this is the end result which takes ages (more than a minute) to run and I know the reason why - as you will also see from looking at the result of the explain - but I just cannot get it sorted.
Just to quickly explain what this query is doing. It is fetching all products from companies that are "connected" to the company where li.nToObjectID = 37. The result also returns some other information about the other companies like its name, company id, etc.
SELECT DISTINCT
SQL_CALC_FOUND_ROWS
p.id,
p.sTitle,
p.sTeaser,
p.TimeStamp,
p.ExpiryDate,
p.InStoreDate,
p.sCreator,
p.sProductCode,
p.nRetailPrice,
p.nCostPrice,
p.bPublic,
c.id as nCompanyID,
c.sName as sCompany,
m.id as nMID,
m.sFileName as sHighResFileName,
m.nSize,
(
Select sName
FROM tblBrand
WHERE id = p.nBrandID
) as sBrand,
(
Select t.sFileName
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as sFileName,
(
Select t.nWidth
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nWidth,
(
Select t.nHeight
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nHeight,
IF (
(
SELECT COUNT(id) FROM tblLink
WHERE
sType = "company"
AND sStatus = "active"
AND nToObjectID = 37
AND nFromObjectID = u.nCompanyID
),
1,
0
) AS bLinked
FROM tblProduct p
INNER JOIN tblMedia m
ON (
m.nTypeID = p.id AND
m.sType = "product"
)
INNER JOIN tblUser u
ON u.id = p.nUserID
INNER JOIN tblCompany c
ON u.nCompanyID = c.id
LEFT JOIN tblLink li
ON (
li.sType = "company"
AND li.sStatus = "active"
AND li.nToObjectID = 37
AND li.nFromObjectID = u.nCompanyID
)
WHERE c.bActive = 1
AND p.bArchive = 0
AND p.bActive = 1
AND NOW() <= p.ExpiryDate
AND (
li.id IS NOT NULL
OR (
li.id IS NULL
AND p.bPublic = 1
)
)
ORDER BY p.TimeStamp DESC
LIMIT 0, 52
Click here to see the output for EXPLAIN. Sorry, just couldn't get the formatting correct.
http://i60.tinypic.com/2hdqjgj.png
And lastly the number of rows for all the tables in this query:
tblProducts
Count: 5392
tblBrand
Count: 194
tblCompany
Count: 368
tblUser
Count: 416
tblMedia
Count: 5724
tblLink
Count: 24800
tblThumbnail
Count: 22207
So I have 2 questions:
1. Is there another way of writing this query which might potentially speed it up?
2. What index combination do I need for tblProducts so that not all the rows are searched through?
UPDATE 1
This is the new query after removing the subqueries and making use of left joins instead:
SELECT DISTINCT DISTINCT
SQL_CALC_FOUND_ROWS
p.id,
p.sTitle,
p.sTeaser,
p.TimeStamp,
p.ExpiryDate,
p.InStoreDate,
p.sCreator,
p.sProductCode,
p.nRetailPrice,
p.nCostPrice,
p.bPublic,
c.id as nCompanyID,
c.sName as sCompany,
m.id as nMID,
m.sFileName as sHighResFileName,
m.nSize,
brand.sName as sBrand,
thumb.sFilename,
thumb.nWidth,
thumb.nHeight,
IF (
(
SELECT COUNT(id) FROM tblLink
WHERE
sType = "company"
AND sStatus = "active"
AND nToObjectID = 37
AND nFromObjectID = u.nCompanyID
),
1,
0
) AS bLinked
FROM tblProduct p
INNER JOIN tblMedia m
ON (
m.nTypeID = p.id AND
m.sType = "product"
)
INNER JOIN tblUser u
ON u.id = p.nUserID
INNER JOIN tblCompany c
ON u.nCompanyID = c.id
LEFT JOIN tblLink li
ON (
li.sType = "company"
AND li.sStatus = "active"
AND li.nToObjectID = 37
AND li.nFromObjectID = u.nCompanyID
)
LEFT JOIN tblBrand AS brand
ON brand.id = p.nBrandID
LEFT JOIN tblThumbnail AS thumb
ON (
thumb.nMediaID = m.id
AND thumb.sType = 'thumbnail'
)
WHERE c.bActive = 1
AND p.bArchive = 0
AND p.bActive = 1
AND NOW() <= p.ExpiryDate
AND (
li.id IS NOT NULL
OR (
li.id IS NULL
AND p.bPublic = 1
)
)
ORDER BY p.TimeStamp DESC
LIMIT 0, 52;
UPDATE 2
ALTER TABLE tblThumbnail ADD INDEX (nMediaID,sType) USING BTREE;
ALTER TABLE tblMedia ADD INDEX (nTypeID,sType) USING BTREE;
ALTER TABLE tblProduct ADD INDEX (bArchive,bActive,ExpiryDate,bPublic,TimeStamp) USING BTREE;
After doing the above changes the explain showed that it is now only searching through 1464 rows on tblProduct instead of 5392.
That's a big query with a lot going on. It's going to take a few steps of work to optimize it. I will take the liberty of just presenting a couple of steps.
First step. Can you get rid of SQL_CALC_FOUND_ROWS and still have your program work correctly? If so, do that. When you specify SQL_CALC_FOUND_ROWS it sometimes means the server has to delay sending you the first row of your resultset until the last row is available.
Second step. Refactor the dependent subqueries to be JOINs instead.
Here's how you might approach that. Part of your query looks like this...
SELECT DISTINCT SQL_CALC_FOUND_ROWS
p.id,
...
c.id as nCompanyID,
...
m.id as nMID,
...
( /* dependent subquery to be removed */
Select sName
FROM tblBrand
WHERE id = p.nBrandID
) as sBrand,
( /* dependent subquery to be removed */
Select t.sFileName
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as sFileName,
( /* dependent subquery to be removed */
Select t.nWidth
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nWidth,
( /* dependent subquery to be removed */
Select t.nHeight
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nHeight,
...
Try this instead. Notice how the brand and thumbnail dependent subqueries disappear. You had three dependent subqueries for the thumbnail; they can disappear into a single JOIN.
SELECT DISTINCT SQL_CALC_FOUND_ROWS
p.id,
...
brand.sName,
thumb.sFilename,
thumb.nWidth,
thumb.nHeight,
...
FROM tblProduct p
INNER JOIN tblMedia AS m ON (m.nTypeID = p.id AND m.sType = 'product')
... (other table joins) ...
LEFT JOIN tblBrand AS brand ON p.id = p.nBrandID
LEFT JOIN tblMedia AS thumb ON (t.nMediaID = m.id AND thumb.sType = 'thumbnail')
I used LEFT JOIN rather than INNER JOIN so MySQL will present NULL values if the joined rows are missing.
Edit
You're using a join pattern that looks like this:
JOIN sometable AS s ON (s.someID = m.id AND s.sType = 'string')
You seem to do this for a few tables. You probably can speed up the JOIN operations by creating compound indexes in those tables. For example, try adding the following index to tblThumbnail: (sType, nMediaID). You can do that with this DDL statement.
ALTER TABLE tblThumbnail ADD INDEX (sType, nMediaID) USING BTREE
You can do similar things to other tables with the same join pattern.

how I can get the next data in mysql

really do not know if you can, but i I need the DATE VENC to be equal to '2013-02-02'.
the values of the column date_pay:
1-2013-01-01
2-2013-02-02
3-0000-00-00
4-0000-00-00
this is my query:
SELECT s.id,
s.name,
s.nro_s,
ts.cat,
SUM( ts.pryce ) AS deuda,
SUM( ts.pryce ) DIV ts.pryce AS c_p,
date_venc = (select max(date_pay) from c ) // the date in question
FROM s
INNER JOIN c
INNER JOIN ts
WHERE s.id = '123'
AND c.id = '123'
AND c.date_pay = '0000-00-00'
AND s.ts = ts.id_ts
Sorry for my english, is very basic.
Greetings.
Assuming date_venc is DATE a possible solution
select *
from s
where s.date_venc=
(select max(cast(SUBSTRING_INDEX(date_pay,'-',-3)as DATE))from c);
also check out sqlfiddle
http://sqlfiddle.com/#!2/64197/1
and your query should probably be modified to,
SELECT s.id,
s.name,
s.nro_s,
ts.cat,
SUM( ts.pryce ) AS deuda,
SUM( ts.pryce ) DIV ts.pryce AS c_p,
date_venc
FROM s
INNER JOIN c
INNER JOIN ts
WHERE s.id = '123'
AND c.id = '123'
AND c.date_pay = '0000-00-00'
AND s.ts = ts.id_ts
AND date_venc = (select max(cast(SUBSTRING_INDEX(date_pay,'-',-3)as DATE)) from c ) // the date in question