SQL Union only counting one query - php

Im trying to count rows in a table. Currently im using this:
$sql = "SELECT COUNT(*)
FROM `friends`
WHERE `user1`='".$user1."'
AND `user2`='".$user2."'
AND `valid`=0
UNION
SELECT COUNT(*)
FROM `friends`
WHERE `user1`='".$user2."'
AND `user2`='".$user1."'
AND `valid`=0";
As you see, user1 can be both $user1 AND $user2. but it does not count the rows after the UNION, it only does the first query before UNION so im ending up with 0 when i actually should be counting 1 row.
How do I solve this?

Another alternative, replace your query with this:
$sql = "SELECT COUNT(*)
FROM `friends`
WHERE (
(`user1`='".$user1."' AND `user2`='".$user2."') OR
(`user1`='".$user2."' AND `user2`='".$user1."')
)
AND `valid`=0";

Your query is actually returning 2 records - 0 for the first count and 1 for the second. You could use a sub-query to SUM() your results...
$sql = "SELECT SUM(A) AS COUNT FROM
(SELECT COUNT(*) AS A
FROM `friends`
WHERE `user1`='".$user1."'
AND `user2`='".$user2."'
AND `valid`=0
UNION
SELECT COUNT(*)
FROM `friends`
WHERE `user1`='".$user2."'
AND `user2`='".$user1."'
AND `valid`=0
)";

Use UNION ALL instead. UNION will exclude duplicate rows.

You can use an even simpler solution:
SELECT COUNT(*)
FROM friends
WHERE
$user1 IN (user1,user2) AND
$user2 IN (user1,user2) AND
valid = 0

Related

php/mysql Merge 2 tables with same Columns correctly

EDIT: Thanks For JoseCarlosPB here is the solution:
SELECT
(select count(DISTINCT userscount) AS duplicates from users1)
+
(select count(DISTINCT userscount) AS duplicates from users2) AS duplicates
FROM dual;
So i have 2 tables and a mysql statement i want to merge 2 tables but there is same column in both.I think There is nothing to do in PHP code i think the problem is in the mysql statement.
my code works(no errors) but it gives unexpected output.i simply want to correctly count userscount here is what i mean:
table1 has 32 users and table2 has 44 users
i thought the output will be 76 users but it is 3244
PHP:
include 'conn00.php';
$sql = "select DISTINCT userscount, count(DISTINCT userscount) AS duplicates from users1 UNION ALL
select DISTINCT userscount, count(DISTINCT userscount) AS duplicates from users2";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo $row["duplicates"];
}
} else {
}
table1:
users1
32
table2:
users2
44
output: 3244 i want the output to be 76
If the solution is in mysql will be better bcz i have more similar sql statements and i want apply the solution for all of it.
thanks for answering
I think you can do it this way, almost like alistaircol said
SELECT
(select count(DISTINCT userscount) AS duplicates from users1)
+
(select count(DISTINCT userscount) AS duplicates from users2) AS duplicates
FROM dual;
Please check article you need Combine two MYSQL table with same column Name
Just comparing to this you need to move count outside of UNION in order to work as you expected
Maybe you could try something like this for your query:
SELECT
(select count(DISTINCT userscount) AS duplicates from users1 group by usercount)
+
(select count(DISTINCT userscount) AS duplicates from users2 group by usercount)
FROM dual;
DUAL is purely for the convenience of people who require that all SELECT statements should have FROM and possibly other clauses. MySQL may ignore the clauses. MySQL does not require FROM DUAL if no tables are referenced.
More info about DUAL: https://dev.mysql.com/doc/refman/8.0/en/select.html
maybe you can change your code query into this to sum the entire counting value
include 'conn00.php';
$sql = "select sum(i) as duplicates from (
select count(DISTINCT userscount) as i from users1 union all
select count(DISTINCT userscount) as i from users2
) x";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo $row["duplicates"];
}
} else {
}
I am not sure, if the semantics of the query was correct, but the syntax must be like this (WHERE clause goes after JOIN and ON):
SELECT users1.text1, users2.name,users2.email,
users1.username
FROM users1
INNER JOIN users2
ON users1.text1=users2.text1
WHERE users1.username = $_SESSION[username]
SELECT * from
( (select count(DISTINCT userscount) AS duplicates from users1)
union all
(select count(DISTINCT userscount) AS duplicates from users2)
) as duplicates
You can also merge in this way.hope it was helpful

Print out a union select

I have the following query:
$query = mysql_query(" ( SELECT naam
FROM users_social
WHERE user_id = 1 )
UNION
( SELECT COUNT(DISTINCT DATE(datetime)) as days
FROM users_social_invoer
WHERE user_id = 1 )"
);
Now I can echo the first part of the query (the 'naam') with the following echo:
echo mysql_fetch_row($row_query[0]);
However echo'ing $row_query[1] does NOT print out the 2nd part of the query (the union select) as I would like to. How do I actually print out that part of the query? thanks
You need JOIN instead of UNION
SELECT us.naam, count(DISTINCT DATE(usi.datetime)) as days
FROM users_social as us
JOIN users_social_invoer as usi
ON us.user_id = usi.user_id
WHERE us.user_id = 1
GROUP BY us.naam

Laravel query builder - Union All with Skip and Take

I need to get data from a table using this query:
(select columns
from tableX
join tableZ
on tableX.id1 = tableZ.other_id)
union all
(select columns
from tableX
join tableZ
on tableX.id2 = tableZ.other_id)
LIMIT num1, num2
Without the LIMIT, I get the correct result with my query builder that look like this (let $first be the first query of select and $second is the other select query):
$first->unionAll($second)->get();
When I try to put skip and/or take, the result is not the same as the first query above.
$first->unionAll($second)->take(num1)->skip(num2)->get();
The result query from the above builder (I got it from DB::getQueryLog()) is something like:
(select columns
from tableX
join tableZ
on tableX.id1 = tableZ.other_id LIMIT num1, num2)
union all
(select columns
from tableX
join tableZ
on tableX.id2 = tableZ.other_id)
which ofcourse yield incorrect result. Does anyone knows what is the work around to make the first query? Thanks!
You need to wrap $firstQuery in another query, like this:
$first->unionAll($second);
$rows = DB::table( DB::raw("({$first->toSql()}) as t") )
->mergeBindings($first->getQuery())
->take(num1)->skip(num2)
->get();
This will result in the following query:
select * from (FIRST_QUERY union all SECOND_QUERY) as t limit num1, num2
One Workaround is to use raw query using DB::select and DB::raw in below sample block...
$num1 = 100; // skip first 100 rows
$num2 = 2; // take only 2 rows
$qry_result = DB::select(DB::raw("select * from
(
(select columns from tableX join tableZ on tableX.id1 = tableZ.other_id)
union all
(select columns from tableX join tableZ on tableX.id2 = tableZ.other_id)
) Qry LIMIT :vskip , :vlimit ") , array('vskip'=>$num1,'vlimit'=>$num2)
);

How to get in MySQL defined names into php?

If I have a mysql query like
(SELECT COUNT(*) FROM data AS amount)
UNION
(SELECT COUNT(*) FROM data WHERE some < 50 AS something)
and then create an array with php like this $row = mysqli_fetch_array($sql, MYSQLI_ASSOC);.
How can I now address each of the AS names. This does not work: echo $row["amount"];. The second question I have is why can't I use AS something when having a WHERE clause?
Try this:
(
SELECT
'amount1' as za_name,
COUNT(*) as za_count
FROM
data
)
UNION
(
SELECT
'amount2' as za_name,
COUNT(*) as za_count
FROM
data
WHERE some < 50
)
Then you can differentiate by $row[za_name] and get the amount $row[za_count]
For the second question : you can use it if you make a temp table :
SELECT
tmp.za_name,
tmp.za_count
FROM (
SELECT
'amount2' as za_name,
COUNT(*) as za_count
FROM
data
WHERE some < 50
) as tmp
In a UNION the row names/aliases for the entire query are whatever they are in the first query.
So if you have
SELECT field1 AS A
UNION
SELECT field2 AS B
Your final result will only have an A field, which will have both field1 and field2.
In your query, you want to alias the COUNT(*), not the table.
(SELECT COUNT(*) AS amount FROM data)
UNION
(SELECT COUNT(*) FROM data WHERE some < 50)
Nor $row['amount'] will be all of the COUNT(*) rows from the entire query.
in your query
(SELECT COUNT(*) FROM data AS amount) UNION (SELECT COUNT(*) FROM data WHERE some < 50 AS something)
You are aliasing the table data to the name amount rather than the sub-query
You have to edit the query this way (aliases on the columns, too)
(SELECT COUNT(*) as amount FROM data)
UNION
(SELECT COUNT(*) as amount FROM data WHERE some < 50 AS something)
This way You are able to address $result['amount'] as a result from the fetch assoc method.

SQL Query - Subquery returns more than one row

Table:
laterecords
-----------
studentid - varchar
latetime - datetime
reason - varchar
My Query:
SELECT laterecords.studentid,
laterecords.latetime,
laterecords.reason,
( SELECT Count(laterecords.studentid) FROM laterecords
GROUP BY laterecords.studentid ) AS late_count
FROM laterecords
I'm getting " MySQL Subquery Returns more than one row" error.
I know a workaround for this query to use the following query:
SELECT laterecords.studentid,
laterecords.latetime,
laterecords.reason
FROM laterecords
Then using php loop to though the results and do below query to get the late_count and echo it out:
SELECT Count(laterecords.studentid) AS late_count FROM laterecords
But i think there might be a better solution ?
The simple fix is to add a WHERE clause in your subquery:
SELECT
studentid,
latetime,
reason,
(SELECT COUNT(*)
FROM laterecords AS B
WHERE A.studentid = B.student.id) AS late_count
FROM laterecords AS A
A better option (in terms of performance) is to use a join:
SELECT
A.studentid,
A.latetime,
A.reason,
B.total
FROM laterecords AS A
JOIN
(
SELECT studentid, COUNT(*) AS total
FROM laterecords
GROUP BY studentid
) AS B
ON A.studentid = B.studentid

Categories