I have mysql table with columns id, pos and status.
And I need to swap pos value of exact id with the nearest smaller pos value. But I need to count only rows with status = 1.
In other words it should work like this:
$pos = mysql_result(mysql_query("select pos from foo where id = $id"),0);
$min = mysql_result(mysql_query("select min(pos) from foo where status = 1"),0);
if($pos != $min){
$i = mysql_result(mysql_query("SELECT pos from foo where pos < $pos ORDER by pos DESC LIMIT 1"),0);
mysql_query("update tbc_sidebar set pos = $i where id = $id");
mysql_query("update tbc_sidebar set pos = pos + 1 where id <> $id AND pos = $i");
}
It works just fine like this, but I think it's not the best solution to have 5 queries because of one simple thing. Is there any way how to put it all into less queries? Thanks!
There are two thing you can do: use a stored procedure [1] [2] or send multiple queries at once with transaction. It kinda depends on which side you want to keep it all.
Also , i would strongly recommend for you to drop the old mysql_* functions as a way of accessing MySQL database. They are more then 10 years old, not maintained anymore and the community has begun the process of deprecation. You should not write new code with mysql_* in 2012. Instead you should learn how to use PDO or MySQLi as the API for accessing DB.
Here are two tutorials you might look at:
PDO Tutorial for MySQL Developers
Introduction to PHP PDO
I have not tried this but it should work. It is not pretty!
UPDATE tbc_sidebar main
INNER JOIN (
SELECT t1.id id1, t1.pos pos1, t2.id id2, t2.pos pos2
FROM tbc_sidebar t1
INNER JOIN tbc_sidebar t2
ON t1.pos > t2.pos
AND t2.status = 1
WHERE t1.id = $id
ORDER BY t2.pos DESC
LIMIT 1
) AS tmp
ON main.id = tmp.id1 OR main.id = tmp.id2
SET main.pos = CASE
WHEN main.id = tmp.id1 THEN tmp.pos2
WHEN main.id = tmp.id2 THEN tmp.pos1
END
Store procedure is a best choice to execute multiple queries together.
Related
This works but is there a shorter(more efficient) way of doing this?
code compares 2 numbers. One is from the most recent record, the other is from 7 records down.
$sql5="SELECT market_cap_rank FROM intelligence WHERE id='$thiscoin' order by day desc limit 0,1";
$row5 = mysqli_fetch_row(mysqli_query($conn, $sql5));
$newest = $row5[0];
$sql6="SELECT market_cap_rank FROM intelligence WHERE id='$thiscoin' order by day desc limit 6,1";
$row6 = mysqli_fetch_row(mysqli_query($conn, $sql6));
$oldest = $row6[0];
$rankdiff=$oldest-$newest;
You can combine both queries in to a single one avoiding round trips to DB server.
Assign ranks to each of the 7 rows after order by with the help of SQL variable. Now, sum() all values by filtering the rows which have rank either 1 or 7.
If rank = 1, add it's negative state.
As a side note, if $thiscoin is coming from user, you can better make parameterized queries to avoid SQL injection attacks using PDO.
Query:
select sum(if(rank = 1,-mcr,mcr)) as diff_mcr
from (
SELECT #rank := #rank + 1 as rank,market_cap_rank as mcr
FROM intelligence,(select #rank := 0) r
WHERE id = '$thiscoin'
order by day desc limit 0,7
) derived
where rank = 1 or rank = 7
Code:
This would simply be
$rankdiff = mysqli_fetch_row(mysqli_query($conn, $sql))[0];
While I was using subqueries, I came across this situation. Could any one explain me which one is efficient and also, the situations where case 1 is better than case 2 or vice versa.
In case 1, I have used 3 subqueries and in total of 4 select operations, it need to perform.
CASE 1
SELECT * FROM t
WHERE Cid = (SELECT cid FROM s WHERE id = $sid)
AND Bid = (SELECT bid FROM s WHERE id = $sid)
AND Eid = (SELECT eid FROM s WHERE id = $sid)
In case 2, I have retrieved some values from database and perform mysql query again. Here mysqli_query is performed twice but in the case 1 only once we have used.
CASE 2
$res = mysqli_query($con,"SELECT cid,bid,eid FROM s WHERE id = $sid");
$row = mysqli_fetch_array($r,MYSQL_ASSOC);
"SELECT * FROM t WHERE Cid = $row[cid] AND Bid = $row[bid] AND Eid = $row[eid]";
or any other better solution? Any help is greatly appreciated. Thanks
Neither. You don't need subqueries when you can use a JOIN.
SELECT t.* FROM t
JOIN s ON t.Cid = s.cid AND t.Bid = s.bid AND t.Eid = s.eid
WHERE s.id = $sid
I am making a stats page about golf for the people I play with. I am trying to pull out of the database the number of times out of all our scorecards that we received birdies (which is -1 under par). It does pull out the -1s per hole, however I noticed that you if you had 2 birdies on a scorecard, it still only counts as 1 birdie instead of 2. I want it to keep counting, so if someone gets 9 birdies, those 9 are added to the total.
$query_p321 = "SELECT t1.*,COUNT(t1.player_id),t2.* FROM scorecards t1 LEFT JOIN courses t2 ON t1.course_id=t2.course_id
WHERE t1.hole1<t2.hole1_par AND t1.hole1>t2.hole1_par-2
OR t1.hole2<t2.hole2_par AND t1.hole2>t2.hole2_par-2
OR t1.hole3<t2.hole3_par AND t1.hole3>t2.hole3_par-2
OR t1.hole4<t2.hole4_par AND t1.hole4>t2.hole4_par-2
OR t1.hole5<t2.hole5_par AND t1.hole5>t2.hole5_par-2
OR t1.hole6<t2.hole6_par AND t1.hole6>t2.hole6_par-2
OR t1.hole7<t2.hole7_par AND t1.hole7>t2.hole7_par-2
OR t1.hole8<t2.hole8_par AND t1.hole8>t2.hole8_par-2
OR t1.hole9<t2.hole9_par AND t1.hole9>t2.hole9_par-2
OR t1.hole10<t2.hole10_par AND t1.hole10>t2.hole10_par-2
OR t1.hole11<t2.hole11_par AND t1.hole11>t2.hole11_par-2
OR t1.hole12<t2.hole12_par AND t1.hole12>t2.hole12_par-2
OR t1.hole13<t2.hole13_par AND t1.hole13>t2.hole13_par-2
OR t1.hole14<t2.hole14_par AND t1.hole14>t2.hole14_par-2
OR t1.hole15<t2.hole15_par AND t1.hole15>t2.hole15_par-2
OR t1.hole16<t2.hole16_par AND t1.hole16>t2.hole16_par-2
OR t1.hole17<t2.hole17_par AND t1.hole17>t2.hole17_par-2
OR t1.hole18<t2.hole18_par AND t1.hole18>t2.hole18_par-2
GROUP BY t1.player_id ORDER BY count(t1.player_id) DESC";
$result_p321 = mysql_query($query_p321);
$number = 1;
while ($row_p321 = mysql_fetch_array($result_p321)) {
$player_id2 = $row_p321["player_id"];
}
and so on..
You'll notice the "-2" in there. That is taking the par minus 2, as I don't want to record if the person is 2 strokes under. Just one stroke under. Any help is appreciated. Thank you.
Oh, also, GROUP BY needs to be used as I don't want to list the player name more than once. Just want it to count all the birdies. I guess my big problem is its not counting more than 1 per row. Thanks.
The problem is the where clause. You need to do the comparisons in the select clause in order to count them:
SELECT t1.*,
sum((t1.hole1 = t2.hole1_par - 1) +
(t1.hole2 = t2.hole2_par - 1) +
. . .
(t1.hole18 = t2.hole18_par - 1)
) as birdies
FROM scorecards t1 LEFT JOIN
courses t2 ON t1.course_id=t2.course_id
GROUP BY t1.player_id
ORDER BY birdies DESC
This uses the MySQL convention that true is 1 and false 0 to add the numbers up. An alternative formulation using standard SQL is:
sum((case when t1.hole1 = t2.hole1_par - 1) then 1 else 0 end) +
Try something like that:
SELECT t1.*, SUM( IF(t1.hole1 = t2.hole1_par-1,1,0) +
IF(t1.hole2 = t2.hole2_par-1,1,0) +
IF(t1.hole3 = t2.hole3_par-1,1,0) +
IF(t1.hole4 = t2.hole4_par-1,1,0) +
-- etc.
IF(t1.hole18 = t2.hole18_par-1,1,0) ) AS birdies
FROM scorecards t1
LEFT JOIN courses t2 ON t1.course_id=t2.course_id
GROUP BY t1.player_id
ORDER BY birdies DESC
I'm trying to update a column in visitors. I'm also using a sub select statement for the SET part of the update query.
UPDATE
visitors AS v
SET
v.IsFirstVisit = (SELECT COUNT(*) FROM visitors AS v2 WHERE ..... LIMIT 1)
However, mySQL returns this error message
#1093 - You can't specify target table 'v' for update in FROM clause
I have no clue why I can't access the 'v' object within the inner select statement. I also don't want to use multiple statements as this would cause a performance issue.
Question: How can I use the 'v' object within the inner select?
Update:
This is the entire query
UPDATE
visitors AS v
SET
IsFirstVisit = (SELECT Count(*) FROM visitors AS v2 WHERE v2.VisitorId < v.VisitorId AND v2.IP = v.IP AND v2.DateTime > v.DateTime [TODO:SUBTRACT30MINUTES] LIMIT 1)
WHERE
VisitorId = "991"
i guess you looking for this
UPDATE
visitors
SET
IsFirstVisit = (SELECT COUNT(*) FROM visitors WHERE ..... LIMIT 1)
edit:
try this
UPDATE
visitors
SET
IsFirstVisit = (SELECT Count(*) FROM visitors v2 inner join visitors v
ON v.VisitorId = v2.VisitorId WHERE v2.IP = v.IP AND v2.DateTime > v.DateTime AND v2.VisitorId < v.VisitorId [TODO:SUBTRACT30MINUTES] LIMIT 1)
WHERE
VisitorId = "991"
The inner join in UPDATE statement won't be a bad idea.
UPDATE
visitors inner join (SELECT COUNT(*) as test FROM visitors v) as v
SET
isfistvisit = v.test;
Another workaround which Im not a big fan of it.
update visitors
set isfistvisit = (
select count(*) from (
select count(*) from visitors
) as x
)
Demo
I want to join these two table but the join key of the second table is in a query string,
page table,
page_id url
1 a
2 c
3 d
system table,
system_id query
1 page_id=1&content=on&image=on
2 type=post&page_id=2&content=on
as you can see that page_id is part of the query string in system table.
so how can I join them like the standard joining table method below?
SELECT*
FROM page AS p
LEFT JOIN system AS s
ON p.page_id = s.page_id
EDIT:
I def can change the system table into something like this,
system_id page_id query
1 1 page_id=1&content=on&image=on
2 2 type=post&page_id=2&content=on
3 NULL type=page
But the reason why I don't want to do this is that the page_id is no need for many certain records. I don't want make a column with too many null.
I would definitely create columns for page_id,content, image and type (and get them indexed). Then the database would be much lighter and would work much faster.
Joining two tables without the common field and data type, is fundamentally wrong IMO.
I will suggest that you extract the page_id and insert it in the database and use a normal join to accomplish what you are searching for.
SO making the columns like
+------------+-----------+---------+
| system_id | page_id | query |
------------------------------------
Here is a snippet with which you are extract the page_id.
$query = 'page_id=1&content=on&image=on';
$queryParts = explode('&', $query);
$params = array();
foreach ($queryParts as $param) {
$item = explode('=', $param);
$params[$item[0]] = $item[1];
}
$page_id = $parems['page_id'];
Then you can go on with the insert and use simple join statement to solve your problem in a proper way.
Update:
Since you are able to change the schema to a feasible one. You dont need to worry about some rows having empty rows on this.
I guess you wanted something like this (MSSQL!):
DECLARE #query VARCHAR(50)
DECLARE #Lenght INT
DECLARE #PageID INT
SET #query = '4kkhknmnkpage_id=231&content=on&image=on'
SET #Lenght = PATINDEX('%&%', substring(#query,PATINDEX('%page_id=%', #query),50)) - 9
SET #PageID = CAST(SUBSTRING(#query,PATINDEX('%page_id=%', #query) + 8,#Lenght) AS INT)
SELECT #PageID -- you can do as you please now :)
OR:
SELECT*
FROM page AS p
LEFT JOIN (SELECT CAST(SUBSTRING(query,PATINDEX('%page_id=%', query) + 8,(PATINDEX('%&%', substring(query,PATINDEX('%page_id=%', query),50)) - 9)) AS INT) AS page_id
FROM system) AS s
ON p.page_id = s.page_id
-- Do as you please again :)
I guess what you really wanted was something like this (MYSQL!):
SET #query := '4kkhknmnkpage_id=231&content=on&image=on';
SET #Lenght := POSITION('&' IN (SUBSTR(#query,POSITION('page_id=' IN #query),50))) - 9;
SET #PageID := CAST(SUBSTR(#query,POSITION('page_id=' IN #query) + 8,#Lenght) AS SIGNED );
SELECT #PageID
OR
SELECT*
FROM page AS p
LEFT JOIN (SELECT CAST(SUBSTR(query,POSITION('page_id=' IN query) + 8,(POSITION('&' IN (SUBSTR(query,POSITION('page_id=' IN query),50))) - 9)) AS SIGNED) AS pageID
FROM system) AS s
ON p.page_id = s.pageID