I am trying to create a single query to display the results of 2 queries. The headings are identical but I just cant seem to figure this out. Here is what I have written:
SELECT ut.question_id, ut.question, ut.response_value, ut.response_text, SUM(ut.total)
FROM
((SELECT survey_questions.id AS 'question_id', survey_questions.question, (survey_responses.sort_order+1) AS 'response_value',
survey_responses.response AS 'response_text', COUNT(survey_responses.response) AS 'total'
FROM voters, group_precincts, voters_surveys, survey_questions, survey_responses
WHERE survey_questions.survey_id = 1
AND voters.id=voters_surveys.voter_id
AND voters.precinct = group_precincts.precincts
AND group_precincts.group_id IN (0)
AND voters_surveys.question_id = survey_questions.id
AND voters_surveys.response_id = survey_responses.id
AND voters_surveys.timestamp BETWEEN '2014-01-01 00:00:00' AND '2014-04-01 00:00:00') AS 'T'
UNION ALL
(SELECT survey_questions.id AS 'question_id', survey_questions.question, (survey_responses.sort_order+1) AS 'response_value',
survey_responses.response AS 'response_text', COUNT(voters_surveys_responses.response_id) AS 'total'
FROM groups, `voters_surveys_responses`, survey_questions, survey_responses
WHERE `voters_surveys_responses`.question_id = survey_questions.id
AND `voters_surveys_responses`.response_id = survey_responses.id
AND `voters_surveys_responses`.timestamp BETWEEN '2014-01-01 00:00:00' AND '2014-04-01 00:00:00'
AND survey_questions.survey_id = 1
AND groups.id IN (0)) AS 'U') AS 'ut'
GROUP BY ut.question_id, ut.response_value;
You have a syntax error, near the UNION ALL. I don't think you can use AS 'T' and AS 'U' where you added them. You are not using these nicknames, so try removing them and re-running.
Another possible problem is that you are grouping by question_id and response_value but also selecting question. You will probably only be able to select fields that you group by, or perform an aggregate function on (like how you apply SUM() to total.
A possible solution is to add question to the GROUP BY.
Related
I have the following query I'm trying to use to spit out each day in a date range and show the # of leads, assignments, & returns:
select
date_format(from_unixtime(date_created), '%m/%d/%Y') as date_format,
(select count(distinct(id_lead)) from lead_history where (date_format(from_unixtime(date_created), '%m/%d/%Y') = date_format) and (id_vertical in (2)) and (id_website in (3,8))) as leads,
(select count(id) from assignments where deleted=0 and (date_format(from_unixtime(date_assigned), '%m/%d/%Y') = date_format) and (id_vertical in (2)) and (id_website in (3,8))) as assignments,
(select count(id) from assignments where deleted=1 and (date_format(from_unixtime(date_deleted), '%m/%d/%Y') = date_format) and (id_vertical in (2)) and (id_website in (3,8))) as returns
from lead_history
where date_created between 1509494400 and 1512086399
group by date_format
The date_created, date_assigned, and date_deleted fields are integers representing timestamps. id, id_lead, id_vertical and id_website are already indexed.
Would adding indexes to date_created, date_assigned, date_deleted, and deleted help make this faster? The issue I'm having is that it is very slow, and I'm not sure an index will help when using date_format(from_unixtime(...
Here is the EXPLAIN:
Looking to your code you could rewrite the query as ..
select
date_format(from_unixtime(date_created), '%m/%d/%Y') as date_format
, count(distinct(h.id_lead) as leads
, sum(case a.deleted = 1 then 1 else 0 end) assignments
, sum(case b.deleted = 0 then 1 else 0 end) returns
from lead_history h
inner join assignments on a a.date_assigned = h.date_created
and a.id_vertical = 2
and id_website in (3,8))
inner join assignments on b b.deleted = h.date_created
and a.id_vertical = 2
and id_website in (3,8))
where date_created between 1509494400 and 1512086399
group by date_format
anyway you shold avoid unuseful () and nested (), avoid unuseful conversion between date and use join instead of subselect .. or at least reduce similar sabuselect using case
PS for what concern the index remember that the use of conversion on a column value invalid the use of related the index ..
I am trying to run a query to get data one time from a client database to our database but a query is taking a lot of time to execute, when I change the order by from primary key user_appoint.id to user_appoint.u_id below is my query
SELECT
CONCAT('D',user_appoint.`id`) AS ApptId,
user_appoint.`u_id`,
tbl_questions.CandAns,
tbl_questions.ExamAns,
tbl_questions.QueNote,
CONCAT("[",GROUP_CONCAT(CONCAT('"',`tbl_investigations`.`test_id`,'":"',tbl_investigations.`result`,'"')),"]") AS CandInv,
CONCAT("[",GROUP_CONCAT(CONCAT('"',`tbl_investigations`.`test_id`,'":"',tbl_investigations.`comments`,'"')),"]") AS IntComm,
IF(tbl_questions.LastUpdatedDateTime>MAX(tbl_investigations.`ModifiedAt`),tbl_questions.LastUpdatedDateTime,MAX(tbl_investigations.`ModifiedAt`)) AS LastUpdatedDateTime,
CONCAT('D',user_appoint.`id`) AS UniqueId
FROM user_appoint
LEFT JOIN tbl_investigations ON tbl_investigations.`appt_id`=user_appoint.`id` AND tbl_investigations.`ModifiedAt`>'2011-01-01 00:00:00'
LEFT JOIN tbl_questions ON tbl_questions.`appt_id` =user_appoint.`id` AND tbl_questions.`LastUpdatedDateTime`>'2011-01-01 00:00:00'
GROUP BY user_appoint.`id`
HAVING LastUpdatedDateTime>'2011-01-01 00:00:00'
ORDER BY user_appoint.`u_id`
LIMIT 0, 2000;
user_appoint.u_id is properly indexed.
Please check the explain plan of your query. And its better to always share explain plan with your original question.
explain format=json
SELECT CONCAT('D',user_appoint.id) AS ApptId, user_appoint.u_id,
tbl_questions.CandAns, tbl_questions.ExamAns, tbl_questions.QueNote,
CONCAT("[",GROUP_CONCAT(CONCAT('"',tbl_investigations.test_id,'":"',tbl_investigations.result,'"')),"]")
AS CandInv,
CONCAT("[",GROUP_CONCAT(CONCAT('"',tbl_investigations.test_id,'":"',tbl_investigations.comments,'"')),"]")
AS IntComm,
IF(tbl_questions.LastUpdatedDateTime>MAX(tbl_investigations.ModifiedAt),tbl_questions.LastUpdatedDateTime,MAX(tbl_investigations.ModifiedAt))
AS LastUpdatedDateTime, CONCAT('D',user_appoint.id) AS UniqueId FROM
user_appoint LEFT JOIN tbl_investigations ON
tbl_investigations.appt_id=user_appoint.id AND
tbl_investigations.ModifiedAt>'2011-01-01 00:00:00' LEFT JOIN
tbl_questions ON tbl_questions.appt_id =user_appoint.id AND
tbl_questions.LastUpdatedDateTime>'2011-01-01 00:00:00' GROUP BY
user_appoint.id HAVING LastUpdatedDateTime>'2011-01-01 00:00:00'
ORDER BY user_appoint.u_id LIMIT 0, 2000;
On looking at your query,I could see lot of concat,aggregate function and join is being performed in single query.
These operations will be performed for all 2000 records as you have set limit on query execution.
This might have caused query to slow down its execution.
You have 2 identical columns with different aliases
CONCAT('D',user_appoint.`id`) AS ApptId,
CONCAT('D',user_appoint.`id`) AS UniqueId
(changed) Assuming NULLs may occur in these date columns then comparing the max() values will overcome any adverse impacts by NULL:
if(max(tbl_questions.lastupdateddatetime) > max(tbl_investigations.`modifiedat`) , max(tbl_questions.lastupdateddatetime), max(tbl_investigations.`modifiedat`)) AS LastUpdatedDateTime
Try this:
SELECT *
FROM (
SELECT
Concat('D', user_appoint.`id`) AS ApptId
, user_appoint.`u_id`
, tbl_questions.candans
, tbl_questions.examans
, tbl_questions.quenote
, Concat("[", Group_concat(Concat('"', `tbl_investigations`.`test_id`, '":"', tbl_investigations.`result`, '"')), "]") AS CandInv
, Concat("[", Group_concat(Concat('"', `tbl_investigations`.`test_id`, '":"', tbl_investigations.`comments`, '"')), "]") AS IntComm
, if(max(tbl_questions.lastupdateddatetime) > max(tbl_investigations.`modifiedat`) , max(tbl_questions.lastupdateddatetime), max(tbl_investigations.`modifiedat`) ) AS LastUpdatedDateTime
, Concat('D', user_appoint.`id`) AS UniqueId
FROM user_appoint
LEFT JOIN tbl_investigations
ON tbl_investigations.`appt_id` = user_appoint.`id`
AND tbl_investigations.`modifiedat` > '2011-01-01 00:00:00'
LEFT JOIN tbl_questions
ON tbl_questions.`appt_id` = user_appoint.`id`
AND tbl_questions.`lastupdateddatetime` > '2011-01-01 00:00:00'
GROUP BY user_appoint.`id`
HAVING lastupdateddatetime > '2011-01-01 00:00:00'
) d
ORDER BY `u_id`
LIMIT 0, 2000
;
HOWEVER
You are using a non-current and non-standard form of GROUP BY clause. MySQL started life allowing this bizarre situation where you could select many columns but only group by one of those. This is completely non-standard for SQL.
In recent versions of MySQL the default settings have changed and using just one column in the GROUP BY clause will cause an error.
So, you may have to change the way you perform the grouping to
GROUP BY
user_appoint.`id`
, user_appoint.`u_id`
, tbl_questions.candans
, tbl_questions.examans
, tbl_questions.quenote
If none of these improve performance please provide the execution plan (as text).
I have a database including certain strings, such as '{TICKER|IBM}' to which I will refer as ticker-strings. My target is to count the amount of ticker-strings per day for multiple strings.
My database table 'tweets' includes the rows 'tweet_id', 'created at' (dd/mm/yyyy hh/mm/ss) and 'processed text'. The ticker-strings, such as '{TICKER|IBM}', are within the 'processed text' row.
At this moment, I have a working SQL query for counting one ticker-string (thanks to the help of other Stackoverflow-ers). What I would like to have is a SQL query in which I can count multiple strings (next to '{TICKER|IBM}' also '{TICKER|GOOG}' and '{TICKER|BAC}' for instance).
The working SQL query for counting one ticker-string is as follows:
SELECT d.date, IFNULL(t.count, 0) AS tweet_count
FROM all_dates AS d
LEFT JOIN (
SELECT COUNT(DISTINCT tweet_id) AS count, DATE(created_at) AS date
FROM tweets
WHERE processed_text LIKE '%{TICKER|IBM}%'
GROUP BY date) AS t
ON d.date = t.date
The eventual output should thus give a column with the date, a column with {TICKER|IBM}, a column with {TICKER|GOOG} and one with {TICKER|BAC}.
I was wondering whether this is possible and whether you have a solution for this? I have more than 100 different ticker-strings. Of course, doing them one-by-one is an option, but it is a very time-consuming one.
If I understand correctly, you can do this with conditional aggregation:
SELECT d.date, coalesce(IBM, 0) as IBM, coalesce(GOOG, 0) as GOOG, coalesce(BAC, 0) AS BAC
FROM all_dates d LEFT JOIN
(SELECT DATE(created_at) AS date,
COUNT(DISTINCT CASE WHEN processed_text LIKE '%{TICKER|IBM}%' then tweet_id
END) as IBM,
COUNT(DISTINCT CASE WHEN processed_text LIKE '%{TICKER|GOOG}%' then tweet_id
END) as GOOG,
COUNT(DISTINCT CASE WHEN processed_text LIKE '%{TICKER|BAC}%' then tweet_id
END) as BAC
FROM tweets
GROUP BY date
) t
ON d.date = t.date;
I'd return the specified resultset like this, adding expressions to the SELECT list for each "ticker" I want returned as a separate column:
SELECT d.date
, IFNULL(SUM(t.processed_text LIKE '%{TICKER|IBM}%' ),0) AS `cnt_ibm`
, IFNULL(SUM(t.processed_text LIKE '%{TICKER|GOOG}%'),0) AS `cnt_goog`
, IFNULL(SUM(t.processed_text LIKE '%{TICKER|BAC}%' ),0) AS `cnt_goog`
, IFNULL(SUM(t.processed_text LIKE '%{TICKER|...}%' ),0) AS `cnt_...`
FROM all_dates d
LEFT
JOIN tweets t
ON t.created_at >= d.date
AND t.created_at < d.date + INTERVAL 1 DAY
GROUP BY d.date
NOTES: The expressions within the SUM aggregates above are evaluated as booleans, so they return 1 (if true), 0 (if false), or NULL. I'd avoid wrapping the created_at column in a DATE() function, and use a range scan instead, especially if a predicate is added (WHERE clause) that restricts the values ofdatebeing returned fromall_dates`.
As an alternative, expressions like this will return an equivalent result:
, SUM(IF(t.process_text LIKE '%{TICKER|IBM}%' ,1,0)) AS `cnt_ibm`
I have a super long complicated mysql query that I could paste here, but I don't think it would help with my question. Basically, I have a subquery that sometimes returns more than one row. When that happens the whole query bombs out. So what I would like to do is have the subquery return it's normal result for that column unless more than one row is returned, then output some specified text in that column. Make sense?
Edit: as requested, I will post my large query. I may be doing it the hard way, but it took me forever to get the query to this point, so I wouldn't know where to begin rewriting it.
SELECT TIME_FORMAT(
TIMEDIFF(
(SELECT PunchDateTime
FROM timeclock_punchlog tp
WHERE PunchEvent = 'breakin'
AND DATE(tp.PunchDateTime) = DATE(U.time)
AND tp.EmpID = U.EmpID),
(SELECT PunchDateTime
FROM timeclock_punchlog tp
WHERE PunchEvent = 'breakout'
AND DATE(tp.PunchDateTime) = DATE(U.time)
AND tp.EmpID = U.EmpID)), '%i min.') AS Lunch
FROM ((SELECT `enter`.EmpID,
`enter`.PunchDateTime AS `time`,
DATE_FORMAT(`enter`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
TIMESTAMPDIFF(SECOND, `enter`.PunchDateTime, '2003-05-01 00:00:00')
AS `delta`
FROM timeclock_punchlog AS `enter`
WHERE `enter`.`In-Out` = 1)
UNION
(SELECT `leave`.EmpID,
`leave`.PunchDateTime AS `time`,
DATE_FORMAT(`leave`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
-TIMESTAMPDIFF(SECOND, `leave`.PunchDateTime, '2003-05-01 00:00:00')
AS `delta`
FROM timeclock_punchlog AS `leave`
WHERE `leave`.`In-Out` = 0)) AS U
LEFT JOIN prempl pe ON u.EmpID = pe.prempl
WHERE DATE(U.`time`) >= ?startDate
AND DATE(U.`time`) < ?endDate
GROUP BY date(U.`time`), EmpID
ORDER BY U.EmpID, U.`time` ASC";
The part that is sometimes returning more than one row is the query defined as "Lunch".
If your query is similar to this:
SELECT id, col1, col2, (SELECT somecol FROM yourtable WHERE ...)
FROM anothertable
....
you could, for example, use some tricks like this:
SELECT id, col1, col2,
CASE WHEN
(SELECT COUNT(*) FROM (..your subquery..) AS s)>1 THEN 'specified text'
ELSE
(..your subquery..)
END AS value_returned_by_your_subquery
FROM anothertable
....
Please see an example here.
But when a query begins to get a little bit too complicated, or when it requires some dirty tricks like this, it is usually better to think again if you really need to do it this way, maybe there's a better and cleaner way, but without seeing the actual query I am not able to help you more :)
I hope this is the appropriate forum to ask for assistance. I have an SQL Query (MySQL) that is not returning the correct records in a Date Range (between two dates). I am happy to answer questions in relation to the query, however if anyone can make suggestions or correct the SQL Query that would be an excellent learning exercise. Thank you.
$raw_query = sprintf("SELECT
swtickets.ticketid AS `Ticket ID`,
swtickettimetracks.tickettimetrackid AS `Track ID`,
swtickets.ticketmaskid AS `TicketMASK`,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Member Company'
ORDER BY
swcustomfieldvalues.customfieldvalueid DESC
LIMIT 1
) AS MemberCompany,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Member Name'
ORDER BY
swcustomfieldvalues.customfieldvalueid DESC
LIMIT 1
) AS MemberName,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Chargeable'
AND
swcustomfieldvalues.fieldvalue = '40'
ORDER BY
swcustomfieldvalues.customfieldvalueid ASC
LIMIT 1
) AS `Chg`,
swtickets.`subject` AS `Subject`,
swtickets.departmenttitle AS Category,
FROM_UNIXTIME(
swtickettimetracks.workdateline
) AS `workDateline`,
FROM_UNIXTIME(
swtickettimetracks.dateline
) AS `dateline`,
swtickettimetracks.timespent AS `Time Spent`,
swtickets.timeworked AS `Time Worked`
FROM
swtickets
INNER JOIN swusers ON swtickets.userid = swusers.userid
INNER JOIN swuserorganizations ON swuserorganizations.userorganizationid = swusers.userorganizationid
INNER JOIN swtickettimetracks ON swtickettimetracks.ticketid = swtickets.ticketid
WHERE
swuserorganizations.organizationname = '%s'
AND (
swtickets.ticketstatustitle = 'Closed'
OR swtickets.ticketstatustitle = 'Completed'
)
AND FROM_UNIXTIME(`workDateline`) >= '%s' AND FROM_UNIXTIME(`workDateline`) <= '%s'
ORDER BY `Ticket ID`,`Track ID`",
$userOrganization,
$startDate,
$endDate
);
As I mentioned, the Query works - however it does not return the records correctly between the two dates.
However, IF I run this simple query against the database :
SELECT swtickettimetracks.tickettimetrackid,
swtickettimetracks.ticketid,
swtickettimetracks.dateline,
swtickettimetracks.timespent,
swtickettimetracks.timebillable,
FROM_UNIXTIME(swtickettimetracks.workdateline)
FROM swtickettimetracks
WHERE FROM_UNIXTIME(swtickettimetracks.workdateline) >= '2013-04-16' AND FROM_UNIXTIME(swtickettimetracks.workdateline) <= '2013-04-18'
I get the correct date range returned. Help? Thank you in anticipation.
Edward.
Unless you are overthinking it, it's all in your different query WHERE clauses...
Your complex query returning the wrong results has
(join conditions between other tables)
AND swuserorganizations.organizationname = '%s'
AND ( swtickets.ticketstatustitle = 'Closed'
OR swtickets.ticketstatustitle = 'Completed' )
AND FROM_UNIXTIME(`workDateline`) >= '%s'
AND FROM_UNIXTIME(`workDateline`) <= '%s'
Your Other query has
FROM swtickettimetracks
WHERE FROM_UNIXTIME(swtickettimetracks.workdateline) >= '2013-04-16'
AND FROM_UNIXTIME(swtickettimetracks.workdateline) <= '2013-04-18'
So I would consider a few things. The first where has
FROM_UNIXTIME >= '%s' and FROM_UNIXTIME <= '%s'
Are you sure the '%s' values are properly formatted to match the '2013-04-16' and '2013-04-18' format sample?
But more importantly, your first query is using the same date range (if correct), but is also only getting those for specific organization name AND (Closed or Completed) records. So, if the second query is returning 100 records, but the main query only 70, then are the other 30 some status other than closed/completed, or a different organization? In addition, if the join tables don't have matching IDs that would prevent those with invalid IDs from being returned. The only way to confirm that is to change to LEFT-JOIN syntax on those tables and see the results.