Join multiple tables with getting total number of rows from 3rd table - php

Trying to join 4 - 5 tables at once as of wanted to grab multiple data which is stored in 5 tables on in 5th table i am trying to count total number of players that have been joined the tournament this is working fine but the main problem which I am facing here is when there is not data in the main table it still return me 1 row with all fields as null except total players showing 0 as it shown not return any rows can anyone help em out below is my query
$getTournamentData = $this->db->select('tournament.*, tournament_meta.meta_title, tournament_meta.meta_description, categories.title AS category, categories.slug AS category_slug, games.game_name, games.slug AS game_slug, count(tournament_players.id) AS total_players');
$getTournamentData = $this->db->join('categories', 'categories.id = tournament.category_id');
$getTournamentData = $this->db->join('games', 'games.game_id = tournament.game_id');
$getTournamentData = $this->db->join('tournament_meta', 'tournament_meta.post_id = tournament.id');
$getTournamentData = $this->db->join('tournament_players', 'tournament_players.tournamentID = tournament.id', 'left');
$dataCond['created_by'] = $this->session->userdata('user_id');
if($id != null) {
$dataCond['tournament.id'] = $id;
}
$getTournamentData = $this->db->where($dataCond);
$getTournamentData = $this->db->get('tournament');
so in return total_players are showing 0 and rest all is null because no data is insterted in the table yet show it should not return any data from the database

You're mixing an aggregate function (count()) with plain column names in your SELECT clause and that is giving unexpected results.
See: Why can't you mix Aggregate values and Non-Aggregate values in a single SELECT?
You can fix this by adding a GROUP BY clause with all of the column names from the SELECT clause, except for the column name that has the count() on it. Be sure to fully type out all of the column names for the tournament.* in the GROUP BY, so use tournament.id, tournament.category_id, tournament.game_id etc instead:
SELECT tournament.*, tournament_meta.meta_title, tournament_meta.meta_description, categories.title AS category, categories.slug AS category_slug, games.game_name, games.slug AS game_slug, count(tournament_players.id) AS total_players
FROM tournament
JOIN categories ON categories.id = tournament.category_id
JOIN games ON games.game_id = tournament.game_id
JOIN tournament_meta ON tournament_meta.post_id = tournament.id
JOIN tournament_players ON tournament_players.tournamentID = tournament.id
GROUP BY
tournament.id, tournament.category_id, tournament.game_id,
-- add other tournament colums here --
tournament_meta.meta_title, tournament_meta.meta_description, categories.title, categories.slug, games.game_name, games.slug
In CodeIgniter (3) this would translate to:
$this->db->select('tournament.*, tournament_meta.meta_title, tournament_meta.meta_description, categories.title AS category, categories.slug AS category_slug, games.game_name, games.slug AS game_slug, count(tournament_players.id) AS total_players');
$this->db->from('tournament');
$this->db->join('categories', 'categories.id = tournament.category_id');
$this->db->join('games', 'games.game_id = tournament.game_id');
$this->db->join('tournament_meta', 'tournament_meta.post_id = tournament.id');
$this->db->join('tournament_players', 'tournament_players.tournamentID = tournament.id');
$this->db->group_by('tournament.id, tournament.category_id, tournament.game_id,
/* add other tournament columns here */
tournament_meta.meta_title, tournament_meta.meta_description, categories.title, categories.slug, games.game_name, games.slug');
Alternatively you can use a subselect, in which case you can remove the join to the tournament_players table:
SELECT tournament.*, tournament_meta.meta_title, tournament_meta.meta_description, categories.title AS category, categories.slug AS category_slug, games.game_name, games.slug AS game_slug, (
SELECT count(id)
FROM tournament_players
WHERE tournament_players.tournamentID = tournament.id) AS total_players
FROM tournament
JOIN categories ON categories.id = tournament.category_id
JOIN games ON games.game_id = tournament.game_id
JOIN tournament_meta ON tournament_meta.post_id = tournament.id
Use with $this->db->query() in CodeIgniter.
I haven't tested these queries obviously, so there may be errors.
Hopefully this'll help you get started.

Related

query for similar results (LIKE %..%) on values that are associated with a different table

I have three TABLES in MySQL:
items, category and intermediate (to allow 'many-to-many' relationships).
TABLE category: TABLE items:
id_category theme id_items part
1 dog 1 tomato
2 fruit 2 rottweiler
3 bird 3 blackbird
4 veg 4 apple
TABLE intermediate:
id_intermediate id_category id_items
1 1 2
2 2 4
3 3 3
4 4 1
There are thousands of entries in each of the tables category and items but 'only' hundreds in the 'relationship' table - intermediate.
now, what I want to do is to query for a certain value, a variable using LIKE '%$var' to check for similar results (spelled word) but only on the COLUMN part in the TABLE items, that have associations or that exist in the TABLE intermediate.
I know how to do the query on the TABLE items (use PHP):
$query = "SELECT * FROM items WHERE part LIKE '%$var%' LIMIT 10";
but as I mentioned, I need only those that have association with the other TABLE category.
I've tried many things, includeding a nested query like:
$query = "SELECT * FROM
(SELECT items.part, items.id_items, id_intermediate, id_items
FROM items JOIN intermediate
WHERE inter.id_items IS NOT NULL)
WHERE items.part LIKE '%$var%'";
but I got this error:"Invalid query: Every derived table must have its own alias", which I don't really understand.
In any case, does any one here know how to solve my problem?
I couldn't find such a question in this forum.
UPDATE (solution):
scaisEdge provided the solution.
$query =
SELECT items.part, items.id_items, inter.id_intermediate, inter.id_items
FROM items
JOIN intermediate on inter.id_items
JOIN category on inter.id_category = category.id AND inter.id_items = items.id_items
WHERE items.part LIKE concat ('%', '$var' , '%') ";
I believe this isn't a duplicate because the other proposals refer to the ALIAS error, which was part of my false attempt. But even with solving the alias error, it had to go through a different approach.
for a specific category (eg:dog ) you could use a join on the 3 tables
and for the filter you could use a cooncat for build the right like string
$query =
SELECT items.part, items.id_items, inter.id_intermediate, inter.id_items
FROM items
JOIN intermediate inter on inter.id_items
JOIN category on inter.id_category = category.id and category.name = 'dog'
WHERE items.part LIKE concat ('%', '$var' , '%') ";
for all the categories you can avoid the 3th join
$query = "
SELECT items.part, items.id_items, inter.id_intermediate, inter.id_items
FROM items
JOIN intermediate inter on inter.id_items
WHERE items.part LIKE concat ('%', '$var' , '%') ";
$query = "SELECT i.* FROM
(SELECT items.part, items.id_items, id_intermediate, id_items
FROM items JOIN intermediate
WHERE inter.id_items IS NOT NULL) as i
WHERE i.items.part LIKE '%$var%'";
This should fix your problem.
"as i" is an alias

query: return all rows even if the count of the associated rows are 0

i have this query:
$oe = OE::select([
'oe.id',
'oe.id_cartao',
'oe.nome',
'oe.email',
\DB::raw('count(trienios.oe_id) as count')
])->leftjoin('trienios', 'trienios.oe_id', '=', 'oe.id')
->groupBy('trienios.oe_id');
which translates to the following query:
select `oe`.`id`, `oe`.`id_cartao`, `oe`.`nome`, `oe`.`email`, count(trienios.oe_id) as count
from `oe`
left join `trienios` on `trienios`.`oe_id` = `oe`.`id`
group by `trienios`.`oe_id
However, if there are no results in the trienios table, the query will only return a single record from the oe table. I want to return all the results from the oe table even if there are no results in the trienios table. How do I do that?
Set group by on primary table
select `oe`.`id`, `oe`.`id_cartao`, `oe`.`nome`, `oe`.`email`, count(trienios.oe_id) as count from `oe` left join `trienios` on `trienios`.`oe_id` = `oe`.`id` group by `oe`.`id`

Adding a field in a MySQL Query

I need to add a field in one of our query. I'm nt a PHP programmer buy I can get my way around a little. The query is:
if (_QUERYSTRING_) {
switch ($intMode) {
case -1:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
9 AS intmode,
Date(orders.dtimeorder) AS datepayment,
orders_costs.dbltotal AS dblamount,
orders_notes.strcod AS strtxn,
0 AS dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
'À recevoir' AS strmode,
NULL AS strvendor
FROM orders
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN orders_notes
ON orders_notes.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
WHERE date(orders.dtimeorder) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'
AND orders.boolshipped = 1
AND orders.boolcanceled = 0
AND orders_costs.boolcod = 1
AND orders_costs.dbltotal > 0
AND NOT EXISTS
(
SELECT *
FROM orders_payments
WHERE orders_payments.intorder = orders.id
AND orders_payments.intmode = 9
AND orders_payments.dblamount > 0)
GROUP BY orders.id
ORDER BY orders.dtimeorder,
orders.id");
break;
default:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
orders_payments.intmode,
Date(orders_payments.dtimepayment) AS datepayment,
orders_payments.dblamount,
orders_payments.strtxn,
orders_payments.dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
payments.strname"._LANG_." AS strmode,
payments.strvendor
FROM orders_payments
JOIN orders
ON orders.id = orders_payments.intorder
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
LEFT JOIN payments
ON payments.id = orders_payments.intmode
WHERE date(orders_payments.dtimepayment) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'".(!empty($intMode) ? "
AND orders_payments.intmode = '".$intMode."'" : NULL)."
GROUP BY orders.id,
orders_payments.intpayment
ORDER BY orders_payments.dtimepayment,
orders.id");
break;
}
The field that needs to be added is orders_addresses.intProvince so it can be displayed in the results. I tried to understand a little but I guess it's a little more complicated than I thought. It does display the province, which are numbers. My question would be, how do I "translate" those numbers by the actual names so it displays "Ontario" instead of 9? The name of the provinces are in another table called Province.
You will need to add another JOIN:
JOIN Province ON orders_addresses.intprovince = Province.x
And in the SELECT part, replace orders_addresses.intprovince by Province.y
where
x = column in table Province that holds the province id
y = column in table Province that holds the province name

php: doctrine 2 and innerJoin condition

I have problem with innerJoin.
Two tables range and product:
table range
id
parent_id
category_id
table product
id
range_id
the query must join range.id with range2.chidren only level 1 and range, range2 with product
ex:
range.id = product.range_id or range2.id = product.range_id:
I want something like :
INNER JOIN product p1_ ON p0_.id = p1_.range_id or p4_.id = p1_.range_id
with doctrine when I write :
->innerJoin('r.products', 'p', Expr\Join::WITH, 'r.id = p.range or rp.id = p.range ')
I got :
INNER JOIN product p1_ ON p0_.id = p1_.range_id AND (p0_.id = p1_.range_id OR p4_.id = p1_.range_id)
someone have solution

SELECT * FROM table WHERE field IN (SELECT id FROM table ORDER BY field2)

I have 4 tables:
categories - id, position
subcategories - id, categories_id, position
sub_subcategories - id, subcategories_id, position
product - id, sub_subcategories_id, prod_pos
Now I'm doing tests to find out what's wrong with my query.
So i want to select sub_subcategories, and to get someting like that:
[[1,2,3,4,5,6], [1,2,3,4,5,6,7]], [[1,2,3,4,5,6], [1,2,3,4]]
Each [] means: big - categories, small - subcategory, and the numbers are position in sub_subcategories. I want the [] to order by their "position" field, so query:
SELECT id FROM sub_subcategories_id
WHERE subcategories_id IN (
SELECT id
FROM subcategories_id
WHERE categories_id IN (
SELECT id FROM categories
WHERE id = 'X' ORDER BY position)
ORDER BY position)
ORDER BY position
is somehow wrong, because I get:
1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,6,6,6,7
Dunno why - does last "ORDER BY position" destroy everything?
You need to apply all of your desired ordering in the outermost query - ORDERing within subqueries doesn't make any sense - the question "is this ID in <this list>?" has the same answer, no matter what order the list is in (indeed, more property, <this list> is a set, which has no order).
So you'll need to get all of the columns you need to order by in your outermost query.
Something like:
SELECT ssi.ID
from
sub_subcategories_id ssi
inner join
subcategories_id si
on
ssi.subcategories_id = si.id
inner join
categories c
on
si.categories_id = c.id
where
c.id = 'X'
order by
c.position,
si.position,
ssi.position
As it stands now, your query would never return a 'set' of numbers as is. If you ignore all the subselects, you're essentially doing:
SELECT id FROM sub_subcategories_id
ORDER BY position
which would only return one column: the sub_sub_categories_id. You'd be better off doing something like:
SELECT cat.id, subcat.id, subsubcat.id
FROM sub_sub_categories AS subsubcat
LEFT JOIN sub_categories AS subcat ON subcat.id = subsubcat.subcategories.id
LEFT JOIN categories AS cat ON cat.id = subcat.category_id
WHERE (cat.id = 'X')
ORDER BY cat.id, subcat.id, subsubcat.id
That'll return 3 columns ordered by the various IDs. If you don't need the individual sub_sub_categories values, and just want them as a single string value, you can mess around with GROUP_CONCAT() and do various bits of grouping:
SELECT cat.id, subcat.id, GROUP_CONCAT(subsubcat.id)
FROM ...
...
WHERE (cat.id = 'X')
GROUP BY cat.id, subcat.id, subsubcat.id
ORDER BY ...

Categories