Select from one table and count from another - php

I would like to know how to select from one table and count from another (loop) using a single query
Table ctagories
------------------------------
cat_id | cat_name | parent_id
------------------------------
1 | General | 0
------------------------------
2 | News | 0
------------------------------
3 | Sports | 1
------------------------------
4 | Test | 0
------------------------------
Table posts
--------------------------------------
post_id| title | c_id | active
--------------------------------------
1 | test | 1 | 1
--------------------------------------
1 | test 1 | 2 | 0
--------------------------------------
1 | test 2 | 1 | 1
--------------------------------------
1 | Test 3 | 3 | 1
--------------------------------------
I want display categories where parent_id=0 (main categories) with the post count (posts where active = 1) in front of it
Ex: General (2 posts)
Can anyone give me a example how to do it with a one query

SELECT
`cat_name`,
(SELECT COUNT(*) FROM `posts` p WHERE p.active =1 AND p.c_id = c.cat_id) as post_count
FROM `category` c
WHERE c.parent_id = 0
ORDER BY `cat_name` ASC

try this query ,you can use subquery with select statement in query.
select cat_name,
(select count(*)
from post
where active=1
and c_id=cat_id
) as countpost
from ctagories
where parent_id=0;

Related

How to compare columns values with sum function in SQL?

I have three tables :
mls_category
points_martix
mls_entry
My first table (mls_category) is like below:
*--------------------------------*
| cat_no | store_id | cat_value |
*--------------------------------*
| 10 | 101 | 1 |
| 11 | 101 | 4 |
*--------------------------------*
My second table (points_martix) is like below:
*----------------------------------------------------*
| pm_no | store_id | value_per_point | max_distance |
*----------------------------------------------------*
| 1 | 101 | 1 | 10 |
| 2 | 101 | 2 | 50 |
| 3 | 101 | 3 | 80 |
*----------------------------------------------------*
My third table (mls_entry) is like below:
*-------------------------------------------*
| user_id | category | distance | status |
*-------------------------------------------*
| 1 | 10 | 20 | approved |
| 1 | 10 | 30 | approved |
| 1 | 11 | 40 | approved |
*-------------------------------------------*
I am using the following query to show the sum of distance with some condition:
SELECT SUM(t1.totald/c.cat_value)
AS total_distance
FROM mls_category c
JOIN
(SELECT SUM(distance) totald, user_id, category
FROM mls_entry
WHERE user_id = 1
AND status = 'approved'
GROUP BY user_id, category) t1
ON c.cat_no = t1.category
This gives me sum 60 as total_distance, that is correct which I wanted.
Now, I want to include the third table (points_matrix) and want to compare my sum(60) is less than or equal to 80(max_distance) then my new value would be 60*3=180.
So, suppose my sum comes 10 then my new value will be 10*1=10 and if my sum comes 25 then my new value will be according to point matrix 25*2=50.
Yon can using MIN() to calculate what value_per_point you need, and the whole sql is like this:
SELECT MIN(b.value_per_point) * d.total_distance FROM points_matrix b
JOIN
(
SELECT store_id, sum(t1.totald/c.cat_value) as total_distance FROM mls_category c
JOIN
(
SELECT SUM(distance) totald, user_id, category FROM mls_entry
WHERE user_id= 1 AND status = 'approved' GROUP BY user_id, category
) t1 ON c.cat_no = t1.category
) d ON b.store_id = d.store_id AND b.max_distance >= d.total_distance
Use Correlated Subquery:
SELECT
dt.total_distance * dt.max_points
FROM (
SELECT SUM(t1.totald/c.cat_value) AS total_distance,
(
SELECT value_per_point
FROM points_martix
WHERE SUM(t1.totald/c.cat_value) >= max_distance
ORDER BY max_distance ASC LIMIT 1
) AS max_points
FROM mls_category AS c
JOIN (
SELECT SUM(distance) AS totald,
user_id,
category
FROM mls_entry
WHERE user_id= 1 AND
status = 'approved'
GROUP BY user_id, category
) AS t1 on c.cat_no = t1.category
) AS dt

Mysql select UNIQUE row on column

I have a table as following:(Ex)
id | vid | time
------------------------
1 | 4 | 1333635317
2 | 4 | 1333635323
3 | 2 | 1333635336
4 | 4 | 1333635343
5 | 5 | 1333635349
I want to be just a row (the last row [ID: 4]) of the same rows[id:1,2,4], how it will output the query?
I mean, as a result of these:
id | vid | time
------------------------
3 | 2 | 1333635336
4 | 4 | 1333635343
5 | 5 | 1333635349
What do i do?
i trying it as:
SELECT * from tbale as t1 where vid = 4 GROUP BY vid ORDER BY id DESC
but doesn't work ORDER BY in my query.
Get the max time per vid and use in to get those rows from the table.
select * from tablename
where (vid,time) in (select vid,max(time)
from tablename
group by vid)
order by id

for each value of one table get and display count number of coresponding values from another table

unfortunately i have to do this in mysql / php . I looked for three days, and there is like 10.000 explantions of this but NONE (and I repeat NONE) works for me. I tried it all. I have to ask, sorry.
I have two tables - articles and control.
table "articles"
------------------
art_id | name |
------------------
1 | aaa |
2 | bbb |
3 | ccc |
4 | ddd |
table "control"
--------------------------------------------
con_id | art_id | data |
--------------------------------------------
1 | 1 | something-a |
2 | 2 | something-b |
3 | 1 | something-a |
4 | 2 | something-c |
5 | 3 | something-f |
art_id exists in both tables. Now what i wanted - for query:
"select * from articles order by art_id ASC" displayed in a table
to have also one cell displaying the count for each of art_id's from table CONTROL...
and so i tried join, left join, inner join - i get errors ... I also tried for each get only one result (for example 2 for everything)... this is semi-right but it displays the array of correct results and it's not even with join!!! :
$query = "SELECT art_id, count(*) as counting
FROM control GROUP BY art_id ORDER BY con_id ASC";
$result = mysql_query($query);
while($row=mysql_fetch_array($result)) {
echo $row['counting'];
}
this displays 221 -
-------------------------------------------------
art_id | name | count (this one from control) |
-------------------------------------------------
1 | aaa | 221 |
2 | bbb | 221 |
3 | ccc | 221 |
and it should be:
for art_id(value1)=2,
for art_id(2)=2,
for art_id(3)=1
it should be simple - like a count of values from CONTROL table displayed in query regarding the "articles" table...
The result query on page for table articles should be:
"select * from articles order by art_id ASC"
-------------------------------------------------
art_id | name | count (this one from control) |
-------------------------------------------------
1 | aaa | 2 |
2 | bbb | 2 |
3 | ccc | 1 |
So maybe i should go with JOIN or with join plus for each... Tried tha too, but then i'm not sure what is the proper thing to echo... all-in-all i'm completely lost here. Please help. Thank you.
So imagine this in two steps:
Get the counts per art_id from the control table
Using your articles table, pick up the counts from step 1
That will give you a query that looks like this:
SELECT a.art_id, a.name, b.control_count
FROM articles a
INNER JOIN
(
SELECT art_id, COUNT(*) AS control_count
FROM control
GROUP BY art_id
) b
ON a.art_id = b.art_id;
Which will give you the results you're looking for.
However, instead of using a subquery, you can do it all in one shot:
SELECT a.art_id, a.name, COUNT(b.art_id) AS control_count
FROM articles a
INNER JOIN control b
ON a.art_id = b.art_id
GROUP BY a.art_id, a.name;
SQL Fiddle demo
SELECT *, (SELECT COUNT(control.con_id) FROM control WHERE control.art_id = articles.art_id) AS count_from_con FROM articles ORDER BY art_id DESC;
If I understood your question right, this query should do the trick.
Edit: Created the tables you have described, and it works.
SELECT * FROM articles;
+--------+------+
| art_id | name |
+--------+------+
| 1 | aaa |
| 2 | bbb |
| 3 | ccc |
| 4 | ddd |
+--------+------+
4 rows in set (0.00 sec)
SELECT * FROM control;
+--------+--------+------+
| con_id | art_id | data |
+--------+--------+------+
| 1 | 1 | NULL |
| 2 | 2 | NULL |
| 3 | 1 | NULL |
| 4 | 2 | NULL |
| 5 | 3 | NULL |
+--------+--------+------+
5 rows in set (0.00 sec)
SELECT *, (SELECT COUNT(control.con_id) FROM control WHERE control.art_id = articles.art_id) AS count_from_con FROM articles ORDER BY art_id ASC;
+--------+------+----------------+
| art_id | name | count_from_con |
+--------+------+----------------+
| 1 | aaa | 2 |
| 2 | bbb | 2 |
| 3 | ccc | 1 |
| 4 | ddd | 0 |
+--------+------+----------------+
You haven't quite explained what you want to accomplish with the print out but here is an example in PHP: (Use PDO instead of mysql_)
$pdo = new PDO(); // Make your connection here
$stm = $pdo->query('SELECT *, (SELECT COUNT(control.con_id) FROM control WHERE control.art_id = articles.art_id) AS count_from_con FROM articles ORDER BY art_id ASC');
while( $row = $stm->fetch(PDO::FETCH_ASSOC) )
{
echo "Article with id: ".$row['art_id']. " has " .$row['count_from_con'].' connected rows in control.';
}
Alternatively with the mysql_ extension:
$result = mysql_query('SELECT *, (SELECT COUNT(control.con_id) FROM control WHERE control.art_id = articles.art_id) AS count_from_con FROM articles ORDER BY art_id ASC');
while( $row = mysql_fetch_assoc($result) )
{
echo "Article with id: ".$row['art_id']. " has " .$row['count_from_con'].' connected rows in control.';
}
This should be enough examples to help you accomplish what you need.

mysql fetch data in where condition

I have 3 table now:
First is : member_username
+-------------+------------------+
| uid | username |
+-------------+------------------+
| 1 | theone |
| 2 | ohno |
| 3 | prayforpr |
+-------------+------------------+
Second is : member_data
+-------------+-------------------+-----------------+
| uid | talk | etc |
+-------------+-------------------+-----------------+
| 1 | talk1 | |
| 2 | talkeee | |
| 3 | iojdfnl | |
+---------------------------------------------------+
Third is : member_level
+-------------+-------------------+-----------------+
| uid | level | fid |
+-------------+-------------------+-----------------+
| 1 | 2 | 1 |
| 1 | 10 | 2 |
| 2 | 1 | 1 |
| 2 | 99 | 2 |
| 1 | 40 | 3 |
| 3 | 50 | 1 |
| 1 | 44 | 4 |
+---------------------------------------------------+
I would like to query data and display the only one uid when member_level is higher in when SUM member_level.level Where fid in 1,2,3.
my query now is like below, but this query is sum all the level including fid 4 also, how to specify only sum in fid 1,2,3? and how do I assign the SUM of member_level.level Where fid in 1,2,3 to $levelKingTotalLevel?
$levelKing = DB::query("SELECT t1.uid,t1.username,t2.talk FROM ".DB::table('member_level')." t3 JOIN ".DB::table('member_username')." t1 ON(t3.uid = t1.uid) JOIN ".DB::table('member_data')." t2 ON (t1.uid = t2.uid) GROUP BY t3.uid ORDER BY SUM(t3.level) DESC LIMIT 1");
while($rowlevelKing = DB::fetch($levelKing)) {
$levelKingTotalLevel = $rowlevelKing['???'];
$levelKingN = $rowlevelKing['username'];
$levelKingUID = $rowlevelKing['uid'];
$levelKingT = $rowlevelKing['talk'];
};
echo "The ".$levelKingN." total level is ".$levelKingTotalLevel." and he talk about ".$levelKingT;
Thank you.
To filter records having fid values as 1, 2 or 3, use IN statement in WHERE clause. Alias totalLevel in select statement will give you total level for a user.
SELECT t1.uid, t1.username, t2.talk, SUM(t3.level) AS totalLevel
FROM member_level t3
JOIN member_username t1
ON (t3.uid = t1.uid)
JOIN member_data t2
ON (t1.uid = t2.uid)
WHERE t3.fid IN (1,2,3)
GROUP BY t3.uid
ORDER BY totalLevel DESC
LIMIT 1

SQL Removing duplicates one row at a time

I have a table where I save all row-changes that have ever occurred. The problem is that in the beginning of the application there was a bug that made a bunch of copies of every row.
The table looks something like this:
copies
|ID |CID |DATA
| 1 | 1 | DA
| 2 | 2 | DO
| 2 | 3 | DO (copy of CID 2)
| 1 | 4 | DA (copy of CID 1)
| 2 | 5 | DA
| 1 | 6 | DA (copy of CID 1)
| 2 | 7 | DO
CID is UNIQUE in table copies.
What I want is to remove all the duplicates of DATA GROUP BY ID that is after one another sorted by CID.
As you can see in the table, CID 2 and 3 are the same and they are after one another. I would want to remove CID 3. The same with CID 4 and CID 6; they have no ID 1 between them and are copies of CID 1.
After duplicates removal, I would like the table to look like this:
copies
|ID |CID |DATA
| 1 | 1 | DA
| 2 | 2 | DO
| 2 | 5 | DA
| 2 | 7 | DO
Any suggestions? :)
I think my question was badly asked because the answer everybody seems to think is the best gives this result:
ID | DATA | DATA | DATA | DATA | DATA | DATA | CID |
|Expected | Quassnoi |
1809 | 1 | 0 | 1 | 0 | 0 | NULL | 252227 | 252227 |
1809 | 1 | 0 | 1 | 1 | 0 | NULL | 381530 | 381530 |
1809 | 1 | 0 | 1 | 0 | 0 | NULL | 438158 | (missing) |
1809 | 1 | 0 | 1 | 0 | 1535 | 20090113 | 581418 | 581418 |
1809 | 1 | 1 | 1 | 0 | 1535 | 20090113 | 581421 | 581421 |
CID 252227 AND CID 438158 are duplicates but because CID 381530 comes between them; I want to keep this one. It's only duplicates that are directly after one another when ordering by CID and ID.
DELETE c.*
FROM copies c
JOIN (
SELECT id, data, MIN(copies) AS minc
FROM copies
GROUP BY
id, data
) q
ON c.id = q.id
AND c.data = q.data
AND c.cid <> q.minc
Update:
DELETE c.*
FROM (
SELECT cid
FROM (
SELECT cid,
COALESCE(data1 = #data1 AND data2 = #data2, FALSE) AS dup,
#data1 := data1,
#data2 := data2
FROM (
SELECT #data1 := NULL,
#data2 := NULL
) vars, copies ci
ORDER BY
id, cid
) qi
WHERE dup
) q
JOIN copies c
ON c.cid = q.cid
This solution empoys MySQL session variables.
There is a pure ANSI solution that would use NOT EXISTS, however, it would be slow due to the way MySQL optimizer works (it won't use range access method in a correlated subquery).
See this article in my blog for performance details for quite a close task:
MySQL: difference between sets
You can use a count in a subquery for this:
delete from copies
where
(select count(*) from copies s where s.id = copies.id
and s.data = copies.data
and s.cid > copies.cid) > 0
// EDITED for #Jonathan Leffler comment
//$sql = "SELECT ID,CID,DATA FROM copies ORDER BY CID, ID";
$sql = "SELECT ID,CID,DATA FROM copies ORDER BY ID, CID";
$result = mysql_query($sql, $link);
$data = "";
$id = "";
while ($row = mysql_fetch_row($result)){
if (($row[0]!=$id) && ($row[2]!=$data) && ($id!="")){
$sql2 = "DELETE FROM copies WHERE CID=".$row[1];
$res = mysql_query($sql2, $link);
}
$id=$row[0];
$data=$row[2];
}
delete from copies c where c.cid in (select max(cid) as max_cid, count(*) as num from copies where num > 1 group by id, data)

Categories