Select DISTINCT with multiple OR in sql query - php

I am trying to write a query with multiple OR and using DISTINICT for multiple column.But the result is NULL what i am missing in my query. Anyone can help me here please.
SELECT DISTINCT
P.user_p_id,
P.surl,
M.user_id,
M.user_p_id
FROM users P, page M
WHERE (P.user_p_id = '$urlid' OR P.surl = '$urlid' OR M.user_id = '$urlid' OR M.user_p_id = '$urlid')

You should do a proper join with an ON clause:
SELECT DISTINCT
P.user_p_id,
P.surl,
M.user_id,
M.user_p_id
FROM users P INNER JOIN page M
ON M.user_id = P.user_p_id
WHERE '$urlid' IN (P.user_p_id, P.surl, M.user_id, M.user_p_id)
I use ON M.user_id = P.user_p_id although it's not clear if you want these columns to be matched.
You may change the type of the JOIN to LEFT if this is what you need.

Related

Having issues with this Mysql query

Hello i'm learning sql and i have some issues with joins(which i have problems understanding them)
I have this issue
#1066 - Not unique table/alias: 'tbl_respuestas'
what the query supposed to do, is count how many people(general,ignore user) has answer 'x', in 'y' question of 'z' survey
SELECT COUNT(*) FROM tbl_respuestas
INNER JOIN tbl_encuesta_usuario ON tbl_encuesta_usuario.user_id = user.id
INNER JOIN tbl_encuesta ON tbl_encuesta.id = tbl_encuesta_usuario.tbl_encuesta_id
INNER JOIN tbl_encuesta_has_tbl_preguntas ON tbl_encuesta_has_tbl_preguntas.tbl_encuesta_id = tbl_encuesta.id
INNER JOIN tbl_preguntas ON tbl_preguntas.id = tbl_encuesta_has_tbl_preguntas.tbl_preguntas_id
INNER JOIN tbl_preguntas_has_tbl_respuestas ON tbl_preguntas_has_tbl_respuestas.tbl_preguntas_id = tbl_preguntas.id
INNER JOIN tbl_respuestas ON tbl_respuestas.id = tbl_preguntas_has_tbl_respuestas.tbl_respuestas_id
WHERE tbl_respuestas.respuesta = 2
line SELECT COUNT(*) FROM tbl_respuestas
and line INNER JOIN tbl_respuestas
does not makes sense, hence the error.
Unless it is what you want then you need to give then different name/alias like below:
SELECT COUNT(*) FROM tbl_respuestas r
INNER JOIN tbl_respuestas r2
Also as a quick note you can rewrite the entire sql like below.
It is good practice to give your tables a name for shorter referencing and makes the sql look a little cleaner.
Also if both tables you are trying to join has the same column name then you can use the keyword USING instead of having to write that long line tbl_encuesta_usuario.user_id = user.id
Please be sure to put r and r2 in its prope place
SELECT COUNT(*) FROM tbl_respuestas r
INNER JOIN tbl_encuesta_usuario u USING user_id
INNER JOIN tbl_encuesta e ON e.id = u.tbl_encuesta_id
INNER JOIN tbl_encuesta_has_tbl_preguntas hp ON hp.tbl_encuesta_id = e.id
INNER JOIN tbl_preguntas p ON p.id = hp.tbl_preguntas_id
INNER JOIN tbl_preguntas_has_tbl_respuestas hr ON hr.tbl_preguntas_id = p.id
INNER JOIN tbl_respuestas r2 ON r2.id = hr.tbl_respuestas_id
WHERE r.respuesta = 2

PHP SQL how the get the exact count from a table

I have two tables with the following columns:
FAMILY - id, ...
PRODUCTS - id, idfamily, type, ...
FAMILY & PRODUCTS are connected with family.id = products.idfamily.
I'm doing pagination over families with filters based on products types, so I'm trying to get the exact count of FAMILY containing almost one product with a specific type.
First query is ok, I get all the families:
if (!isset($_GET['type']) || $_GET['type'] == 'all') {
$query_family=mysql_query("SELECT * FROM family");
}
$count=mysql_num_rows($query_family);
// result = 166
Unfortunately, the following query is wrong:
} else {
$query_family=mysql_query("
SELECT * FROM family f LEFT JOIN products p ON f.id = p.idfamily
WHERE p.type = '$_GET[type]'
");
}
$count=mysql_num_rows($query_family);
// result = 500+
it's wrong because I get all the products with a type, but I'm trying to get the number of families containing products with the selected type ($_GET[type]).
Thank you
You should have
SELECT distinct f.id from family f LEFT JOIN products p on f.id = p.idfamily WHERE p.type = '$_GET[type]' in the second query
I think.
SELECT COUNT(*) as nbr FROM family
INNER JOIN products ON products.idfamily = family.id
WHERE product.type = ".intval($_GET['type'])."
GROUP BY family.id
Avoid the mysql_ driver, use PDO or mysqli instead. Don't forget to protect you from sql injections too.
To get the count of families with a specified type, use
SELECT * FROM family f INNER JOIN products p ON f.id = p.idfamily
WHERE IFNULL(p.type, 'notspecified') = '$_GET[type]'
With INNER JOIN instead of LFET JOIN you get only rows where a connection between f.id and p.idfamily exist. By LEFT JOIN, all family rows are returned with NULL values in the fields of product table.
So when p.type is NULL, your p.type = '$_GET[type]' evaluates always to NULL, and your filtering will not work as expected. For this reason, use IFNULL.
You can try below code:
$query_family=mysql_query("
SELECT COUNT(f.id) AS cnt FROM family f
INNER JOIN products p ON f.id = p.idfamily
WHERE p.type = '$_GET[type]'");
Also try to use mysqli not mysql.
And you don't have to use mysql_num_rows, you can get the right number directly from mysql:
$query = "SELECT COUNT(DISTINCT f.id) ".
"FROM family f ".
"LEFT JOIN products p ON f.id = p.idfamily ".
"WHERE p.type = '".$_GET['type']."'";
Use INNER JOIN instead of LEFT.

nested queries and calculations all in the same query - is it possible?

I am running a MySQL query to get all "users" with current orders.
(It is possible for a user to have more than 1 associated orders in the db/query).
However i also want to get the total order value for each user and total order count for each user that is being returned (within the below query).
I could do these calculations in PHP, but feel it is possible and would be neater all done within the same SQL query (if possible).
This is the basic query with no attempt to make the above calculations
SELECT u.UserID, u.UserName,
o.OrdersID, o.OrderProductName, o.OrderProductQT, o.OrderTotalPrice, o.tUsers_UserID, o.tOrderStatus_StatusID, o.OrderDate, o.OrderDateModified, o.OrderVoid, o.tProducts_ProductID,
os.OrderStatusName,
ud.UserDetailsName, ud.UserDetailsPostCode,
p.ProductName, p.ProductImage1
FROM tusers u
INNER JOIN torders o ON o.tUsers_UserID = u.UserID
INNER JOIN torderstatus os ON os.OrderStatus_StatusID = o.tOrderStatus_StatusID
INNER JOIN tuserdetails ud ON ud.tUsers_UserID = u.UserID
LEFT JOIN tproducts p ON p.ProductID = o.tProducts_ProductID
WHERE o.tOrderStatus_StatusID = ?
GROUP BY u.UserID
ORDER BY OrdersID DESC
I have tried various nested select queries, but none of them work (right)
Is what i want to do possible in SQL or should i just do it all in PHP once i have the returned query results?
Any advice is much appreciated
You can embed the slightly modified queries into another query. For instance:
SELECT userid, SUM(orderid) FROM orders GROUP BY userid
and
SELECT userid, SUM(distinct productid)
FROM
orders o
INNER JOIN orderlines ol on ol.orderid = o.orderid
GROUP BY
userid
can be combined to:
SELECT
u.userid
u.fullname,
(SELECT SUM(orderid)
FROM orders o
WHERE o.userid = u.userid) as ORDERCOUNT,
(SELECT SUM(distinct productid)
FROM
orders o
INNER JOIN orderlines ol on ol.orderid = o.orderid
WHERE
o.userid = u.userid) as UNIQUEPRODUCTS
FROM
users u
Note that the latter query will return all users and will return NULL for ORDERCOUNT or UNIQUEPRODUCTS when the subquery doesn't return anything (when a user doesn't have orders). Also, the query will fail when a subquery returns more than 1 row, which should never happen in the example I posted.

How to write JOIN QUERY for 4 tables in the below condition

I have 4 tables ACCOUNTS_TABLE , LINKS_TABLE, GROUPS_TABLE, KEYS_TABLE
I need to get all accounts details which is of acct_type xx with count of Links, groups& keywords . I have tried this query but it gives all count as 0
SELECT
acc.acct_id, acc.acct_type, count(link.id) as link_count, link.account,
groups.camp_id, count(groups.id) as group_count, count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id AND acct_type='xx'
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.camp_id=link.id
GROUP BY acc.acct_id
My required output should be like this
Any one please help me to slove this problem
You probably should use COUNT(DISTINCT ....).
SELECT acc.acct_id, COUNT(DISTINCT link.id), COUNT(DISTINCT groups.id), COUNT(DISTINCT keyword.key_id)
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id AND acct_type = 'advertiser'
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.id = link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id
EDIT
Amended to use the updated join conditions, etc:-
SELECT acc.acct_id, acc.acct_type, COUNT( DISTINCT link.id ) , COUNT( DISTINCT groups.id ) , COUNT( DISTINCT keyword.key_id )
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.camp_id=link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id, acc.acct_type
You could try something like this:
SELECT ACC.Id
,( SELECT COUNT (*) FROM Links L WHERE L.AccountId = ACC.Id ) AS CountOfLinks
,( SELECT COUNT (*) FROM Groups G WHERE G.AccountId = ACC.Id ) AS CountOfGroups
FROM ( SELECT Id FROM Accounts Acc WHERE Acc.Type = 'some type' ) ACC
I've rejigged your code a bit (see below) for a few reasons:
It's helpful (for me anyway) to write my SELECT statements always in a certain way - with anything that is not being grouped placed first, and ideally putting things in same order as my JOINs and doing the same in my GROUP BY
I put anything which restricts my FROM table into the WHERE not the JOIN to make it clearer what I'm trying to do and also to make it easier to modify later on.
I also like to ensure it's well laid out to make it easier to scan for issues.
Take this rearranged query and read through it to make sure you are getting the behaviour you're expecting.
PS I'm not sure about your table names and quotation style - I usually use back ticks (`) and would never put dots (.) in my table names. If you put these in as placeholders that's fine but they could lead to trouble for you if they are real.
SELECT
acc.acct_id,
-- if you don't group by these then you need to remove them as they will just return the first values based on mysql behaviour
acc.acct_type,
link.account,
groups.camp_id,
-- these counts will only count where an ID is present which seems like what you're after
count(link.id) as link_count,
count(groups.id) as group_count,
count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.id=link.id
WHERE acct_type='advertiser'
GROUP BY acc.acct_id,
-- only use these if you intend to group by them
acc.acct_type,
link.account,
groups.camp_id DESC
SELECT acct_type,
count(acct_type),
count(l.id),
count(g.id),
count(key_id)
FROM accounts a
LEFT JOIN links l ON (l.account = a.acct_id)
LEFT JOIN groups g ON (g.camp_id = l.id)
LEFT JOIN keysTable k ON k.group_id = g.id
GROUP BY acct_type HAVING acct_type = 'xx';
SQL Fiddle Validated: http://www.sqlfiddle.com/#!2/f4b6a/20
SELECT
accounts_table.acct_id,
accounts_table.acct_type,
COUNT(DISTINCT links_table.id) AS link_count,
COUNT(DISTINCT groups_table.id) AS group_count,
COUNT(DISTINCT keys_table.key_id) AS key_count
FROM
accounts_table
LEFT JOIN
links_table
ON links_table.account = accounts_table.acct_id
LEFT JOIN
groups_table
ON groups_table.camp_id = links_table.id
LEFT JOIN
keys_table
ON keys_table.camp_id = links_table.id
WHERE
acct_type = 'xx'
GROUP BY
accounts_table.acct_id,
accounts_table.acct_type
ORDER BY
link_count DESC,
group_count DESC,
key_count DESC
Edited answer to match updated question - this should do what you've asked for.
This should do what you've asked for, SQL fiddle here - http://www.sqlfiddle.com/#!2/f4b6a/20

mysql distinct statement not working

$query = "SELECT DISTINCT t.task_id, e.url,e.error_id, p.page_rank, e.scan_status, e.url_is_route,e.url_is_route,e.forbidden_word,e.google_host_fail,e.google_cache_fail,e.google_title_fail,e.robots_noindex_nofollow,e.xrobots_noindex_nofollow,e.title_fetch_warn,e.h1_fail,e.h2_fail,e.h3_fail,e.h1_warn,e.h2_warn,e.h3_warn
FROM `error_report` AS e
INNER JOIN task_pages AS t ON t.task_id=e.task_id
INNER JOIN `pages` AS p ON p.page_id=t.page_id
WHERE t.task_id=" . $this->task_id ;
I want the query to be distinct only by t.task_id. The problem is that when I add more fields..the query isnt distinct anymore. Is there still a way to select distinct by t.task_id only?
instead of distinct use group by
$query = "SELECT t.task_id, e.url,e.error_id, p.page_rank, e.scan_status, e.url_is_route,e.url_is_route,e.forbidden_word,e.google_host_fail,e.google_cache_fail,e.google_title_fail,e.robots_noindex_nofollow,e.xrobots_noindex_nofollow,e.title_fetch_warn,e.h1_fail,e.h2_fail,e.h3_fail,e.h1_warn,e.h2_warn,e.h3_warn
FROM `error_report` AS e
INNER JOIN task_pages AS t ON t.task_id=e.task_id
INNER JOIN `pages` AS p ON p.page_id=t.page_id
WHERE t.task_id=" . $this->task_id
."group by t.task_id";
If you add more fields, you should use GROUP BY iirc.
Note that your extra fields should be aggregates, e.g. MIN, MAX, etc. MySQL is more forgiving and shows the first value of each field (though not reliably apparently).

Categories