I have the following sql which selects the most recurring row first based on the column "reported"
$datan = mysql_query("
SELECT *, COUNT(reported) AS ct
FROM profile_reports
WHERE open = '1'
GROUP BY reported
ORDER BY ct DESC
LIMIT 1
") or die(mysql_error());
I want my sql to also check which 'reporter' (each is a number associated with a user) has the best percentage of useful reports, which is determined this way:
((raction > 0 AND raction < 99 AND open = '0' AND reporter = 'reporter') / (reporter = 'reporter' AND open = '0')) * 100
...and show the rows with highest percentage first. It's a little tricky because no initial reporter is set.
Here's a sample table:
+----+----------+----------+-------+----------+
| id | reporter | reported | open | raction |
+----+----------+----------+-------+----------+
| 1 | 24 | 26 | 0 | 3 |
| 2 | 24 | 23 | 0 | 0 |
| 3 | 24 | 29 | 1 | |
| 4 | 12 | 29 | 0 | 4 |
| 5 | 12 | 29 | 1 | |
| 6 | 24 | 21 | 1 | 0 |
+----+----------+----------+-------+----------+
I want it to see that there are more reports about user 29(column: reported), then check which reporting user(column: reporter) has the best percentage (based on the line of code above), in this case user 12, and display their report
Its actually pretty easy in just take the sums of your conditions and divide. In order to get the "Reported" correctly you'll need to use an inline view to find the highest report.
SELECT pr.*,
( Sum(pr.raction > 0
AND pr.raction < 99
AND pr.open = '0'
AND pr.reported = t.reported) / Sum(pr.reported = t.reported
AND pr.open = '0') ) * 100 AS
usefull
FROM profile_reports pr,
(SELECT reported
FROM profile_reports
WHERE open = '1'
GROUP BY reported
ORDER BY Count(reported) DESC
LIMIT 1) t
GROUP BY reporter
ORDER BY usefull DESC
LIMIT 1
demo
Output
| ID | REPORTER | REPORTED | OPEN | RACTION | USEFULL |
-------------------------------------------------------
| 4 | 12 | 29 | 0 | 4 | 100 |
I haven't done everything for you. You will have to decide what to do if the divisor is zero
Note in just about everything but MySQL you would need to use CASE
SUM ( CASE WHEN raction > 0 AND .... THEN 1 ELSE 0 END) / ....
Related
I'm trying to output the number of distinct results from a row where two other tables factor into the equation, but I'm not sure how to make this work. Here's what I have. I have counted the total times which a word appears in the database.
$total = "SELECT word, count(word) total FROM Table WHERE Word = 'Apples'";
total = 9. Ok, good. That was easy.
+-------------+--------------+--------------+--------------+
| BookID (INT)| chapter (INT)| page (INT) | word (VCHAR) |
+-------------+--------------+--------------+--------------+
| 40 | 1 | 8 | Apples |
| 40 | 1 | 8 | Apples |
| 40 | 1 | 15 | Apples |
| 40 | 4 | 23 | Apples |
| 50 | 3 | 15 | Apples |
| 50 | 6 | 15 | Apples |
| 51 | 13 | 1 | Apples |
| 52 | 2 | 3 | Apples |
| 60 | 8 | 1 | Apples |
+-------------------------------------------+--------------+
Now, here's where I'm needing some assistance. I want to find the number of times the word is used on a DISTINCT page in each chapter of each book. So, based on the table above, I am expecting the total to be 8. I'm close with this code, but I can't find the next step.
$pages = "SELECT COUNT(DISTINCT page) AS num FROM Table WHERE word = 'Apples' GROUP BY BookID, chapter, page";
This gives me:
1
1
1
1
1
1
1
1
So, I'm getting the correct number. 8 rows. Now I just need to add those up and output them as a single number. 8. I've looked into SUM, but that doesn't seem to work (if I'm mistaken, please show me how I should include it.)
You may simply take the sum of your current query as a subquery:
SELECT SUM(num) AS total
FROM
(
SELECT COUNT(DISTINCT page) AS num
FROM yourTable
WHERE word = 'Apples'
GROUP BY BookID, chapter, page
) t;
This question already has an answer here:
How Can Calculate Credits,Debits & Balance in the general ledger?
(1 answer)
Closed last year.
I am trying code in php with mysql and I want to calculate running balance based on the type of transaction. My database table is as per below
id | amt | type | date
----+---------+----------+-----------
1 | 70000 | Cr | 01-01-2022
2 | 8000 | Dr | 01-01-2022
3 | 60000 | Cr | 02-01-2022
4 | 50000 | Dr | 02-01-2022
5 | 90000 | Cr | 03-01-2022
6 | 28000 | Dr | 03-01-2022
And I want the result as per below, if type = Cr then ADD and if type = Dr then SUBTRACT and auto calcuate running BALANCE where initial value to be ZERO
id | Dr | Cr | date | balance
----+----------+---------+-------------+----------
1 | 0 | 70000 | 01-01-2022 | 70000
2 | 8000 | 0 | 01-01-2022 | 62000
3 | 0 | 60000 | 02-01-2022 | 122000
4 | 50000 | 0 | 02-01-2022 | 72000
5 | 0 | 90000 | 03-01-2022 | 162000
6 | 28000 | 0 | 03-01-2022 | 134000
The following is the PHP script I'm currently using
<table>
<tr><th>Date</th><th>IN</th><th>OUT</th><th>Balance</th></tr>
<?php
$conn=mysqli_connect("details hidden");
$sql="SELECT * FROM table_name WHERE type IN ('Dr', 'Cr') ORDER BY date DESC";
$query=mysqli_query($conn, $sql);
while ($row=mysqli_fetch_array($query)) {
echo '<tr>';
echo '<td>'.$newdate = date('d-m-y', strtotime($row['date'])).'</td>';
if ($row['type']==Dr){
echo '<td>'.$row['amt'].'</td>';
echo '<td></td>';}
elseif ($row['type']==Cr){
echo '<td></td>';
echo '<td>'.$row['amt'].'</td>';}
else {
echo '<td></td>;
echo '<td></td>;}
echo '</tr>';
}
?>
</table>
Any help would be helpful.
You can use the sum window function to get the result you want:
select id,
case when `type` = 'Dr' then `amt` else 0 end as Dr,
case when `type` = 'Cr' then `amt` else 0 end as Cr,
date,
sum(case when `type` = 'Dr' then -`amt` when `type` = 'Cr' then `amt` end) over(order by date rows unbounded preceding) as balance
from table_name;
Fiddle
I have two tables in MySQL:
visits
points
visits table looks like the following:
+-------+-------------------+-----------+
| id | date | user_id |
+-------+-------------------+-----------+
| 1 |2014-08-01 05:23:00| 43 |
| 2 |2014-08-01 14:41:00| 21 |
| 3 |2014-08-02 23:54:00| 43 |
| 4 |2014-08-03 03:21:00| 43 |
| 5 |2014-08-03 04:19:00| 34 |
| 6 |2014-08-03 11:33:00| 43 |
| 7 |2014-08-04 12:21:00| 43 |
| 8 |2014-08-05 01:55:00| 43 |
| 9 |2014-08-06 06:13:00| 43 |
| 10 |2014-08-07 19:47:00| 43 |
+-------+-------------------+-----------+
points table looks like the following:
+-------+-------------------+-----------+-------+----------+
| id | date | user_id | points| status |
+-------+-------------------+-----------+-------+----------+
| 1 |2014-08-01 04:33:00| 43 | 10 | 0 |
| 2 |2014-08-02 05:21:00| 21 | 23 | 0 |
| 3 |2014-08-02 09:01:00| 43 | 32 | 1 |
| 4 |2014-08-02 01:21:00| 43 | 21 | 0 |
| 5 |2014-08-03 23:23:00| 34 | 54 | 0 |
| 6 |2014-08-04 20:34:00| 43 | 11 | 0 |
| 7 |2014-08-04 17:54:00| 43 | 9 | 0 |
| 8 |2014-08-04 03:45:00| 43 | 34 | 0 |
| 9 |2014-08-06 08:23:00| 43 | 76 | 0 |
| 10 |2014-08-07 11:43:00| 43 | 52 | 0 |
+-------+-------------------+-----------+-------+----------+
I want execute only 1 query and achieve the following.
I'd like to count the rows in the visits table where the user_id = 43 and the date is between 2014-08-01 and 2014-08-03.
I also want to count the rows, sum the points in the points table where user_id = 43 and the date is between 2014-08-01 and 2014-08-03 and the status is 0.
After that, in the same query, I'd like to select the same as above, but in a different timeframe, like: 2014-08-04 and 2014-08-07.
Is there any query out there which can solve this problem for me?
(I'm actually doing this because I'd like to get data for one of my jQuery chart which is called: Morris.js. I'd like to get 12 datasets if the visitor selects a time range and divide it based on the days, the visitor selected. For example: if he selects: 2014-08-01 till 2014-08-01, I want to display him 12 datasets of that day. But if he selects for example: 2014-08-01 till 2014-08-06, then I'd want to display him the data for the 6 day divided by 12.)
If you don't understand something here, just let me know and I'll explain it better. The point is that I'd like to collet the datasets and draw the chart based on the time range to the visitor. Is that above MySQL logic a good solution for my issue?
EDIT:
As per request I'm showing the desired result in here:
+---------------------+-----------+-------+-------+-------------+
| date | user_id | points| visits| points_count|
+---------------------+-----------+-------+-------+-------------+
|2014-08-01-2014-08-03| 43 | 31 | 4 | 2 |
|2014-08-04-2014-08-07| 43 | 182 | 4 | 5 |
+---------------------+-----------+-------+-------+-------------+
I hope I've calculated everything correctly.
ok so this took a little work because you have to join the two tables independantly of eachother.. the reason being is because one can't have the status of 1 and the other can.. so with that in mind this query will return exactly what you want.
QUERY:
SELECT
t.join_date as 'Time Frame',
t1.user_id,
t.num_visits,
t1.num_points,
t1.total_points
FROM
( SELECT
CASE
WHEN DATE(date) >= '2014-06-01' AND DATE(date) <= '2014-07-10' THEN 1
WHEN DATE(date) >= '2014-08-05' AND DATE(date) <= '2014-08-07' THEN 2
ELSE 3
END AS grouping_col,
CONCAT(MIN(DATE(date)), ' - ', MAX(DATE(date))) as join_date,
COUNT(id) as num_visits
FROM visits
WHERE user_id = 43
GROUP BY grouping_col
)t
LEFT JOIN
( SELECT
CASE
WHEN DATE(date) >= '2014-06-01' AND DATE(date) <= '2014-07-10' THEN 1
WHEN DATE(date) >= '2014-08-05' AND DATE(date) <= '2014-08-07' THEN 2
ELSE 3
END AS grouping_col,
CONCAT(MIN(DATE(date)), ' - ', MAX(DATE(date))) as join_date,
user_id,
COUNT(id) as num_points,
SUM(points) as total_points
FROM points
WHERE user_id = 43
AND status = 0
GROUP BY grouping_col
)t1 ON t1.grouping_col = t.grouping_col
WHERE t.grouping_col IN(1, 2) OR t1.grouping_col IN(1, 2)
NOTE:
you can add as many timeframes to this by just adding more rows to the CASE statement...
SEE DEMO:
FIDDLE
A better option may be to actually use a stored procedure and set a beginning date param and an end date param so you can pick any dates you want
The only approach which comes to mind is to do two distinct query and use UNION ALL
SELECT *
FROM
(SELECT
count(v.id) AS visit_count,
count(p.id) AS point_count,
sum(p.points) AS points
FROM visits v1
JOIN points p1
ON v1.user_id = p1.user_id
WHERE v1.user_id = 43
AND DATE(v1.date) BETWEEN '2014-08-01' AND '2014-08-03'
AND p1.status = 0
UNION ALL
SELECT
count(v.id) AS visit_count,
count(p.id) AS point_count,
sum(p.points) AS points
FROM visits v2
JOIN points p2
ON v2.user_id = p2.user_id
WHERE v2.user_id = 43
AND DATE(v2.date) BETWEEN '2014-08-04' AND '2014-08-07'
AND p2.status = 0
) temp
You could try:
select count(id)
from visits
join points on points.user_id = visits.user_id
where date between 2014-08-04 00:00:00 and 2014-08-07 00:00:00
and visits.user_id = 43
I got the following MySQL table:
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 4 | -1 | 2 |
| 5 | 4 | 2 |
| 6 | 4 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
>| 9 | -1 | 2 |
>| 10 | -1 | 1 |
>| 11 | -1 | 2 |
+----+--------+------+
> = original comment
The entries with answer = -1 are the original comments.
The entries with answer != -1 are answers to the comment with the respective id.
Furthermore there are types of comments (in this case 1 or 2).
Now I want to retrieve the original comments (for a specified type and a specified limit) and their answers (type and limit do not matter). Further it would be great to group the result by the two types (again, only the original comment's type matters for grouping).
A query result for type=1 and limit=2 should look like that (not grouped yet):
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
+----+--------+------+
I have tried several kinds of queries for hours now, can I implement it without a procedure? What would the procedure look like?
I would appreciate your help a lot.
Use a subquery to get 2 original comments of type-1 first, then join the table again to get both original comments and responses.
select b.*
from (
select id
from answers
where type = 1 and answer = -1
limit 2) a
join answers b on a.id = b.id or a.id = b.answer;
fiddle
To select 2 original comments of each type, you'll need to use user-defined-variable to index each original comment. The following code indexes the first original comment as 1, the second one as 2, and so on, then resets to 1 when the type changes. Finally in the final where statement filter out indices greater than 2.
select b.*, a.idx
from (
select id, #idx:=if(#type=a.type,#idx+1,1) idx, #type:=a.type
from (select id, type from answers2 where answer is null order by type) a
join (select #type:=null, #idx:=null) b) a
join answers2 b on a.id = b.id or a.id = b.answer
where a.idx <= 2;
fiddle
Store it as a separate column or even a different table if you are worried about too much data duplication. You are overthinking it.
I'm having a hard time figuring this one out. I have this database that will get bigger sooner or later and it looks like this.
est_id |mat_id | est_qty | qty_rec
2 | 29 | 50 | 0
3 | 29 | 70 | 0
8 | 29 | 100 | 0
Now, what I want to accomplish is to update a single row until est_qty and qty_rec are equal then move to the other one after. I started a code but its not working.
foreach($mat_id as $mat_id_key => $mat){
while($rec_qty > 0){
$remBal = $est_qty[$mat_id_key] - $qty_rec[$mat_id_key];
if(($remBal - $rec_qty) >= 0){
mysql_query('UPDATE `estimates` SET `qty_rec` = `qty_rec` + '.$rec_qty.' WHERE `proj_id` = "'.$proj_id.'" AND `mat_id` = "'.$mat[$mat_id_key].'"');
}
}
}
In this code, each row will go in to loop, until its going to satisfy the condition which is the difference between est_qty and $rec_qty is a greater than or equal to zero it will update that row.
For instance, the user input 30 as the $rec_qty, the database will now look like:
est_id |mat_id | est_qty | qty_rec
2 | 29 | 50 | 30
3 | 29 | 70 | 0
8 | 29 | 100 | 0
When the user inputs the second time around, for instance 40 as $rec_qty, the database will now look like:
est_id |mat_id | est_qty | qty_rec
2 | 29 | 50 | 50
3 | 29 | 70 | 20
8 | 29 | 100 | 0
Here is a set-based single query to do this, though it uses a triangular-join:
update est as e
join (
select *
, case when needed - room_below > room then room else needed - room_below end as to_add
from (
select *
, est_qty - qty_rec as room
, (select coalesce(sum(est_qty - qty_rec), 0) from est where mat_id = a.mat_id and est_id < a.est_id) as room_below
, 30 as needed -- Variable?
from est as a
) as b
) as c on e.est_id = c.est_id
set e.qty_rec = e.qty_rec + c.to_add
where e.mat_id = 29 -- Variable?
and c.to_add > 0;
It should be noted that this has no logic to deal with an overflow condition, where you're trying to insert a larger number than can be fit in the existing records (you'd possibly have to insert a new record to hold the remainder).
There is a SqlFiddle demo here.
Because your table does not have a unique id, your UPDATE will update all rows that match proj_id and mat_id. Thus, if you start out with:
mat_id | est_qty | qty_rec
29 | 50 | 30
29 | 70 | 0
29 | 100 | 0
and add 40, you will end up with:
mat_id | est_qty | qty_rec
29 | 50 | 70
29 | 70 | 70
29 | 100 | 70
or even:
mat_id | est_qty | qty_rec
29 | 50 | 40
29 | 70 | 40
29 | 100 | 40
...depending on which row was found first.
Add a primary key to your table, then update the record based on this ID.
You dont need the loop. These two queries should suffice:
mysql_query("set #remain := $rec_qty");
mysql_query(
"update estimates
set qty_rec = #remain,
qty_rec = qty_rec - (#remain := if( qty_rec > est_qty, qty_rec - est_qty, 0)
where mat_id = $matId
order by est_id"
);
$matId is the mat_id you want to update.