can't find where this error ocur - php

SELECT e.emp_id, concat(e.firstname,' ', e.middlename,' ',e.lastname) as EmployeeName ,
(select * from mst_attendance where status='Present' AND a.current_date > '#2008-09-29%#' GROUP BY substr('emp_id',0,5) HAVING COUNT(*)>1 ORDER BY a.emp_id='5') as PresentDays,
a.emp_id, a.current_date, a.status, a.in_time, a.out_time FROM mst_attendance a
INNER JOIN mst_employee e ON a.emp_id=e.emp_id where e.status='active'
and e.flag='Y' and e.role='employee' and e.emp_id='5' ORDER BY a.created asc LIMIT 1
Here I want to know the present days of an employee. But I get the error:
1241 - Operand should contain 1 column(s)..

Instead of
(select * from mst_attendance where status='Present' AND a.current_date > '#2008-09-29%#' GROUP BY substr('emp_id',0,5) HAVING COUNT(*)>1 ORDER BY a.emp_id='5') as PresentDays
The query should be something like
(select column_name from mst_attendance where status='Present' AND a.current_date > '#2008-09-29%#' GROUP BY substr('emp_id',0,5) HAVING COUNT(*)>1 ORDER BY a.emp_id='5') as PresentDays

Related

query with dependent subqueries too slow

select mt.from_user, mt.to_user, mt.group_id, g.name, g.created_by as adminuser,
msg.*,
(
SELECT id
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgid,
(
SELECT CreatedDate
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgDate
from user_thread as t
left join message_thread as mt ON t.thread_id = mt.id
left join group_master as g ON mt.group_id = g.id
left join group_member as gm ON gm.group_id = g.id
left join messages as msg ON t.thread_id = msg.thread_id
where ( gm.user_id=275
or msg.from_id=275
or msg.to_id=275
)
and t.status = 'Active'
group by mt.id
order by msgDate DESC
This takes about 50 sec.
In above code, I have try to split above query and note that below subquery take too much time to execute. Can I convert subquery into join. please help me. I am stuck.please note that all tables which are joined are necessary.
(
SELECT id
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgid,
(
SELECT CreatedDate
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgDate
First, You are misusing a notorious MySQL extension to GROUP BY. This will probably cause your results to be unpredictable. Read this. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Second, You have a couple of nested dependent subqueries. The first of them is this.
(select id
from messages
where t.thread_id = thread_id
and id NOT IN (select message_id
from message_deleted
where user_id=275
and status='deleted')
order by CreatedDate DESC limit 1) as msgid
Such nested dependent subqueries perform notoriously badly. They're even worse when they contain LIMIT clauses. Your route to fixing this is refactoring into an independent query and then JOINing it.
This may work as a replacement for the query to find the most recent undeleted message on the thread.
SELECT MAX(m.id) id, m.thread_id
FROM messages m
LEFT JOIN message_deleted d
ON m.id = d.id
AND d.user_id = 275
AND d.status = 'deleted'
WHERE d.id IS NULL
GROUP BY m.thread_id
This uses the LEFT JOIN .... IS NULL pattern in place of NOT IN. It's faster. It uses the MAX(id) method of finding the most recent row in a table in place of the ORDER BY CreatedDate DESC LIMIT 1 method, which is also much faster. It's good because it's guaranteed to generate either 0 or 1 row per value of thread_id. That means you can use it in a LEFT JOIN ... ON ... thread_id operation and not add any rows to your result set.
You can test this subquery by running it. Then you JOIN it, as if it were a table, to the rest of your query, something like this.
SELECT whatever,
q.id, r.CreatedDate
FROM whatever
LEFT JOIN (
SELECT MAX(m.id) id, m.thread_id
FROM messages m
LEFT JOIN message_deleted d
ON m.id = d.id
AND d.user_id = 275
AND d.status = 'deleted'
WHERE d.id IS NULL
GROUP BY m.thread_id
) q ON q.id = t.id
LEFT JOIN messages r ON r.id = q.id
The second LEFT JOIN operation here is used to retrieve the CreatedDate value of the newest undeleted message from the messages table.

Select results from table1 based on entries on table2

I have 2 tables;
banner_views (id, b_id, b_date)- this record a banner view every time it gets displayed
banners_dynamic (id, status, static_iname, static_keywords, static_url, static_alt, static_type, static_image, b_views, b_clicks) - stores the banner data
I would like to select 3 banners_dynamic results which have had the least views in the last 7 days.
I did put somethign together (see below) but I realised it was grabbing the total views for all banner rather than uniquely by id.
SELECT *,
(SELECT COUNT(*) FROM banner_views v WHERE v.b_date >= DATE(NOW()) - INTERVAL 7 DAY) as post_count
FROM banners_dynamic b
WHERE static_keywords LIKE '%test%' AND b.status='1' AND b.static_type='1'
ORDER BY post_count ASC LIMIT 3
Can anyone point me in the correct direction?
You must join both banners_dynamic table and your subquery with corresponding banner IDs:
SELECT
b.*, p.b_count
FROM
banners_dynamic b
INNER JOIN (
SELECT
b_id,
COUNT(*) AS b_count
FROM
banner_views v
WHERE
v.b_date >= DATE(NOW() - INTERVAL 7 DAY)
GROUP BY
b_id
) p on p.b_id = b.id
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
ORDER BY
p.b_count ASC
LIMIT 3
UPDATE: You can do it even without subquery:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
INNER JOIN banner_views v ON v.b_id = b.id
WHERE
v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
AND b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;
If you want to include banners without any views (count=0) then you must do a LEFT JOIN:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
LEFT JOIN banner_views v ON v.b_id = b.id
AND v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;

Select with inner join

i need select some data from two tables ,
please help me use inner join for this selection .
players in selction2 must not be in selection1...
first select :
$rs = "SELECT *
FROM `player`
WHERE `status`=1 AND `credit`>=1 AND `username` NOT LIKE '$user'
ORDER BY ls ASC,credit DESC
LIMIT 0 ,10;
Second: this players must remove from result of selection1
$rs2 = "SELECT *
FROM `ip_log`
WHERE `playerid`='$ui' AND `win`='1' AND `date`='$date' ";`
You can use LEFT JOIN for this:
This shows the log messages for everyone not in selection 1.
SELECT l.*
FROM ip_log AS l
LEFT JOIN
(SELECT username
FROM player
WHERE status = 1 AND credit >= 1 AND username NOT LIKE '$user'
ORDER BY ls ASC, credit DESC
LIMIT 10) AS p
ON l.player = p.username
WHERE win = 1 and date = '$date'
AND p.username IS NULL
This shows the top 10 player data, except the ones with log messages in selection 2
SELECT p.*
FROM player AS p
LEFT JOIN ip_log AS l ON l.player = p.username AND l.win = 1 AND l.date = '$date'
WHERE p.status = 1 AND p.credit >= 1 AND p.username NOT LIKE '$user'
AND l.player IS NULL
ORDER BY p.ls ASC, p.credit DESC
LIMIT 10
In both cases, testing a column in the second table with IS NULL makes it return only the rows in the first table that don't have a match in the second table. See
Return row only if value doesn't exist
You can do it with LEFT JOIN
SELECT player.*,ip_log.* FROM `player` LEFT JOIN `ip_log` ON player.id!=ip_log.playerid GROUP BY player.id

Select top score only from MySQL database

I have a MySQL statement that pulls back the top 15 scores from a table of users.
select #rownum:=#rownum+1 'rank', driverName, teamColour, totalScore, totalTime, didTyreChange from entries p, (SELECT #rownum:=0) r WHERE totalTime > 1000 and progress = 19 order by totalScore desc, totalTime asc limit 15
The conditions are, that the player must have completed all the questions (where progress = 19) and the final time must be more than 1 second (totalTime > 1000). The statement also returns their rank as a variable (#rownum:=#rownum+1 'rank').
The result of this query is the following
What I now want to do, is extend the results to only show a players top score. I have had a look at DISTINCT and GROUP BY but get these results with the following GROUP BY statement
select #rownum:=#rownum+1 'rank', driverName, teamColour, totalScore, totalTime, didTyreChange from entries p, (SELECT #rownum:=0) r WHERE totalTime > 1000 and progress = 19 group by driverName order by totalScore desc, totalTime asc limit 15
and nowhere with DISTINCT as I get error code 1064. I have tried both
select #rownum:=#rownum+1 'rank', DISTINCT(driverName), teamColour, totalScore, totalTime, didTyreChange from entries p, (SELECT #rownum:=0) r WHERE totalTime > 1000 and progress = 19 order by totalScore desc, totalTime asc limit 15
and
select DISTINCT driverName, #rownum:=#rownum+1 'rank', teamColour, totalScore, totalTime, didTyreChange from entries p, (SELECT #rownum:=0) r WHERE totalTime > 1000 and progress = 19 order by totalScore desc, totalTime asc limit 15
Neither provides the desired results. I'm wondering if there is an easy way to achieve this within the statement, or to do it on the PHP side of things instead.
The desired resultL
viper 1 9810
Maverick 2 25420
Racer roasty 3 28850
.. .
... 15
In other words, no user should appear in the results twice, only the quickest totalTime is displayed for each user.
Slimmed down SQLFiddle here http://sqlfiddle.com/#!2/36d3dc/7 (8000 char limit reached).
SELECT #i:=#i+1 rank, a.*
FROM
( SELECT x.*
FROM entries x
JOIN (SELECT drivername, MIN(totaltime) min_totaltime FROM entries WHERE progress = 19 AND totaltime > 1000 GROUP BY drivername) y
ON y.drivername = x.drivername
AND y.min_totaltime = x.totaltime
) a
, (SELECT #i:=0) i
ORDER
BY totalScore desc, totalTime asc;
http://sqlfiddle.com/#!2/36d3dc/17
If I understood your problem correctly then below query will help you:
select *,#rownum:=#rownum+1 as 'rank' from (select * from (select driverName, teamColour, totalScore, totalTime, didTyreChange from entries p WHERE totalTime > 1000 and progress = 19 order by totalScore desc, totalTime asc )a group by driverName)c , (select #rownum:=0)f
This should do:
select #rownum:=#rownum+1 'rank', driverName, totalScore, MIN(totalTime)
from entries p, (SELECT #rownum:=0) r
WHERE totalTime > 1000 and progress = 19
group by driverName
order by totalScore desc, totalTime asc
http://sqlfiddle.com/#!2/36d3dc/20/0

mySQL - Using two JOINs in one query?

I am trying to use two JOIN statements in one query,
$sqlsorgu = mysql_query("SELECT *, COUNT(*), AVG(clicks), AVG(scrolls), AVG(spent)
FROM track where referid='".$memberr."' GROUP BY referer ORDER BY id desc limit 15
JOIN
(
select id, country, num, num*100/total pct
from (SELECT id,country, count(*) as num
FROM track GROUP BY country
ORDER BY num desc limit 5) x
join (select count(*) total from track) y
) tc on t.id = tc.id") or die(mysql_error());
but I am getting this error:
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 'JOIN ( select id, country, num, num*100/total pct from (SELECT id,country' at line 1
What is the correct way to use it ?
GROUP BY/ WHERE/ Order by come after join statements. Try reording like:
"SELECT *, COUNT(*), AVG(clicks), AVG(scrolls), AVG(spent)
FROM track t
JOIN
(
select id, country, num, num*100/total pct
from (SELECT id,country, count(*) as num
FROM track GROUP BY country
ORDER BY num desc limit 5) x
join (select count(*) total from track) y
) tc on t.id = tc.id
where referid='".$memberr."'
GROUP BY referer
ORDER BY tc.id desc limit 15

Categories