Combining several database table together? - php

I have two tables tour_foreign&tour_foreign_residence in database and want merger this two table together that get output from PHP code as following example:
My tables and values it:
I want get as output tour_foreign.id = tour_foreign_residence.relation :
One-week tour of Istanbul_1 | 88888 & 99999 $ 112233 $ 445566 | Three nights and two days | 15:29
One-week tour of Istanbul_2 | 55555 & 66666 $ 77777 | Three nights and two days | 12:03
One-week tour of Istanbul_3 | 11111 & 22222 $ 33333 $ 44444 | Three nights and two days | 12:03
My try is this but it don't give to me what that I want in above:
$this -> db -> query("
SELECT
#rownum := #rownum + 1 rownum,
tour_foreign.id,
tour_foreign.name,
tour_foreign_residence.name_re,
tour_foreign.term,
tour_foreign.time_go,
tour_foreign.time_back,
tour_foreign.type_of_vehicle
FROM tour_foreign
INNER JOIN tour_foreign_residence
ON ( tour_foreign.id = tour_foreign_residence.relation )
JOIN (SELECT #rownum := 0) r
WHERE tour_foreign.name LIKE "%' . $find . '%"
OR tour_foreign_residence.name_re LIKE "%' . $find . '%"
")
How can fix it?

Try using GROUP_CONCAT() to join the names from you tour_foreign_residence table

Not sure why you are joining on #rownum, it might be messing with your result set. Try taking it out and see if it works.
Your inner join looks ok, except I have never seen it with the wrapped parens, but I suspect it will work as expected. To test your query you could remove the complicated where clause and just put something like where tour_foreign.id = 1.
Something like:
SELECT
tf.*
FROM
tour_foreign AS tf
INNER JOIN
tour_foreign_residence AS tfr
ON
tfr.relation = tf.id
WHERE
tf.id = 1
I implemented aliases for your longer table names (tf, and tfr) as they are easier to work with.

Related

How can I filter one column by two AND conditions?

The question has been resolved. But if you have a "better" or another way to do it then feel free to add a comment! Thanks all for reading! :)
I'm trying to make a dynamic query. Everything is working perfectly except for one thing. I've Google'd for days but I can't figure out how I can make the following work;
SELECT project.name, project.description, track.name, track.description
, SDG.position, SDG.title, SDG.description
, sprint_numbers.number, sprint_options.option
, resources.name, resources.description
, URLs.URL
FROM project INNER JOIN track ON project.track_id = track.id
INNER JOIN project_SDG ON project.id = project_SDG.project_id
INNER JOIN SDG ON project_SDG.SDG_id = SDG.id
INNER JOIN sprint ON sprint.project_id = project.id
INNER JOIN sprint_numbers ON sprint_numbers.id = sprint.sprint_number_id
INNER JOIN sprint_options ON sprint_options.id = sprint.sprint_option_id
INNER JOIN resources ON project.id = resources.project_id
INNER JOIN URLs ON URLs.id = resources.id
WHERE 1=1
AND MATCH (project.name) AGAINST (:name_project)
AND MATCH (project.description) AGAINST (:description_project)
AND SDG.id = :SDG_1
AND SDG.id = :SDG_2
The query executes but does not return anything. The problem is that the SDG.id can't be true to both :SDG_1 and :SDG_2.
Using the OR operator works, but that does not return it the way I want. It must "act" as an AND operator. (:SDG_1 & :SDG_2 are the names of the PHP variables that bind to the SQL statement parameters.)
The query should filter for both values. The values given to :SDG_1 and :SDG_2 must both exist in the SDG.id column of the project_SDG table. If the value of :SDG_1 exists, but :SDG_2 not, then the query should not return anything.
I found this on StackOverflow but it did not work for me: SELECTING with multiple WHERE conditions on same column
I hope someone can help me out.
EDIT: minimal reproducible example
QUERY:
SELECT * FROM project
INNER JOIN project_SDG ON project.id = project_SDG.project_id
INNER JOIN SDG ON project_SDG.SDG_id = SDG.id
WHERE SDG.id = 1 AND SDG.id = 7 AND SDG.id = 14 AND SDG.id = 17
Project table
+------------------+---------------------------+------------+
| id name | description | track_id |
+------------------+---------------------------+------------+
| 1 project name | This is a description 2 | |
+------------------+---------------------------+------------+
SDG table
+-----+-----------+-------------+---------------------------------------------+
| id | position | title | description |
+-----+-----------+-------------+---------------------------------------------+
| 1 | 1 | SDG 1 to 17 | There're multiple SDGs ranging from 1 to 17 |
| 17 | 17 | SDG 1 to 17 | There're multiple SDGs ranging from 1 to 17 |
+-----+-----------+-------------+---------------------------------------------+
project.SDG (bridge-table)
+------------+--------+
| project.id | SDG.id |
+------------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
+------------+--------+
You want for each project.id both values :SDG_1 and :SDG_2 to exist for SDG.id, so use this in the WHERE clause:
WHERE 1=1
AND MATCH (project.name) AGAINST (:name_project)
AND MATCH (project.description) AGAINST (:description_project)
AND project.id IN (
SELECT project_id
FROM project_SDG
WHERE SDG_id IN (:SDG_1, :SDG_2)
GROUP BY project_id
HAVING COUNT(DISTINCT SDG_id) = 2
)
Could you provide a minimal reproducible example for your query?
Generally speaking, one field cannot be equal to two different values in the same time. So, you have either mixed up the logical operators or you need two different fields.
I can assume that in your case there may be several related records with different values. In this case, you need to join the same table twice with different aliases. Let's say as SDG1 and SDG2. After that you can compare
... `SDG1`.id = :SDG_1 AND `SDG2`.id = :SDG_2
Update:
The win trick is groupping. You can enumerate all required SDG IDs and count how many of them is in group. Just for example in case of two IDs:
SELECT project.id
FROM project
JOIN project_SDG ON project_SDG.project_id = project.id
JOIN SDG ON SDG.id = project_SDG.SDG_id
WHERE SDG.id IN(1,2)
GROUP BY project.id
HAVING COUNT(*) = 2
See my sandbox here: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/0
If you need all project's fields, you have to put this into sub-query as
... WHERE id IN ( subquery here )
Subquery example: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/1
I have already answered here, but I have another approch.
1. Find bunch of IDs assotiated with some project
To find project IDs we can test lonely pivot table without any join:
SELECT project_id FROM project_SDG
WHERE SDG_id IN(1,2,6)
GROUP BY project_id HAVING COUNT(*) = 3
it gives us list of Project IDs
2. Access all project fields and add extra conditions
SELECT project.*
FROM project
JOIN (
SELECT project_id FROM project_SDG
WHERE SDG_id IN(1,2,6)
GROUP BY project_id HAVING COUNT(*) = 3
) AS ids ON ids.project_id = project.id
WHERE
MATCH(project.name) AGAINST ('project') AND
MATCH(project.description) AGAINST ('sit')
you can play with it here: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/3
3. Prepare query on the PHP side
I will use known technique to prepare SQL statement.
$ids = [1, 2, 6]; // it can come from request parameters
$text1 = 'project';
$text2 = 'sit';
// build ?,?,?,... pattern
$qmarks = implode(',', array_fill(0, count($ids), '?'));
// Use SQL query above
$sth = $dbh->prepare("
SELECT project.*
FROM project
JOIN (
SELECT project_id FROM project_SDG
WHERE SDG_id IN({$qmarks})
GROUP BY project_id HAVING COUNT(*) = ?
) AS ids ON ids.project_id = project.id
WHERE
MATCH(project.name) AGAINST (?) AND
MATCH(project.description) AGAINST (?)
");
$sth->execute(array_merge($ids, [count($ids), $text1, $text2]));
$records = $sth->fetchAll();

How to match the chracters with # in oracle query

Incident Table
I have Incident Table like below i need to match the client list in client table. How can i do that in oracle ?
INCIDENT_ID |CLIENTS_LIST |
------------|-----------------|
56 |A001##A05M##A0AS |
Client Table
BO_NAME |COMPANYID
----------------------|---------
Test1 |A001
Test2 |A0AS
Test3 |A05M
Test4 |A0BT
Im trying to match the companyid with clients_list but there is no result.
Tried Query
SELECT DISTINCT INCIDENT_ID,
CLIENTS_LIST,
REPLACE(CLIENTS_LIST, '##', ',') AS client_id,
cl.BO_NAME,
COMPANYID
FROM incident ir
INNER JOIN Client cl
ON cl.companyid IN (REPLACE(CLIENTS_LIST, '##', ','))
Expected Output
BO_NAME |COMPANYID
----------------------|---------
Test1 |A001
Test2 |A0AS
Test3 |A05M
I see a design problem there, you should always save each value in a separate column, or in a separate table with a 1-to-many relationship.
Now, you aren't going to make an efficient query, or at least, as efficient as it could be. With that in mind, you could use LIKE Operator in combination with CROSS JOIN This query is very unnefficient, but it should work:
SELECT *
FROM incidentTable t, clientTable c
WHERE t.IncidentId = 56 AND '#' || t.ClientList || '#' LIKE '%#' || c.CompanyId || '#%'
you can use oracle instr
with inc(INCIDENT_ID,CLIENTS_LIST) as (select 56, 'A001##A05M##A0AS' from dual),
Client(BO_NAME,COMPANYID) as
(select 'Test1','A001' from dual union all
select 'Test2','A0AS' from dual union all
select 'Test3','A05M' from dual union all
select 'Test4','A0BT' from dual )
select *
from inc, client
where instr(clients_list,companyid) > 0
INCIDENT_ID CLIENTS_LIST BO_NAME COMPANYID
----------- ---------------- ------- ---------
56 A001##A05M##A0AS Test1 A001
56 A001##A05M##A0AS Test2 A0AS
56 A001##A05M##A0AS Test3 A05M

Count and concatenate MySQL entries

Essentially, I have a table that is like this:
FirstName, LastName, Type
Mark, Jones, A
Jim, Smith, B
Joseph, Miller, A
Jim, Smith, A
Jim, Smith, C
Mark, Jones, C
What I need to do is be able to display these out in PHP/HTML, like:
Name | Total Count Per Name | All Type(s) Per Name
which would look like...
Mark Jones | 2 | A, C
Jim Smith | 3 | B, A, C
Joseph Miller | 1 | A
Jim Smith | 3 | B, A, C
Jim Smith | 3 | B, A, C
Mark Jones | 2 | A, C
I have spent time trying to create a new table based off the initial one, adding these fields, as well as looking at group_concat, array_count_values, COUNT, and DISTINCT, along with other loop/array options, and cannot figure this out.
I've found a number of answers that count and concatenate, but the problem here is I need to display each row with the total count/concatenation on each, instead of shortening it.
How about doing it like this?
SELECT aggregated.* FROM table_name t
LEFT JOIN (
SELECT
CONCAT(FirstName, ' ', LastName) AS Name,
COUNT(Type) AS `Total Count Per Name`,
GROUP_CONCAT(Type SEPARATOR ',') AS `All Type(s) Per Name`
FROM table_name
GROUP BY Name) AS aggregated
ON CONCAT(t.FirstName, ' ', t.LastName) = aggregated.Name
Without an ORDER BY clause, the order the rows will be returned in is indeterminate. Nothing wrong with that, by my personal preference is to have the result to be repeatable.
We can use an "inline view" (MySQL calls it a derived table) to get the count and the concatenation of the Type values for (FirstName,LastName).
And then perform a join operation to match the rows from the inline view to each row in the detail table.
SELECT CONCAT(d.FirstName,' ',d.LastName) AS name
, c.total_coount_per_name
, c.all_types_per_name
FROM mytable d
JOIN ( SELECT b.FirstName
, b.LastName
, GROUP_CONCAT(DISTINCT b.Type ORDER BY b.Type) AS all_types_per_name
, COUNT(*) AS total_count_per_name
FROM mytable b
GROUP
BY b.FirstName
, b.LastName
) c
ON c.FirstName = d.FirstName
AND c.Last_name = d.LastName
ORDER BY d.FirstName, d.LastName
If you have an id column or some other "sequence" column, you can use that to specify the order the rows are to be returned; same thing in the GROUP_CONCAT function. You can omit the DISTINCT keyword from the GROUP_CONCAT if you want repeated values... 'B,A,B,B,C',

How can I retrieve a comma-separate list of linked ids in a 3-way MYSQL join?

I'm creating a book tagging system (i'm sure this has been done tons of times before), and I'd like to create a view that gives me each book, with its tags' names.
I have three tables:
books ( id, name)
tags (id, name)
bookTags (id, book, tag)
And I'd like to have one view
booksInfo (books.id, books.name, [comma-separated-tags.names], [tagids])
With my current view (in the sql fiddle below), I get duplicate rows, one for each tag-book pair.
I'd love to get something like this:
BOOKID NAME TAGS TAGIDS
------ ----------- -------------------- ---------
1 1984 Dystopian, Political 3, 4
2 White Fang Dogs, Nature 5, 9
3 Bible Religion, History 6, 10
4 1776 Political, History 4, 10
I created a sqlfiddle here: http://sqlfiddle.com/#!2/74b57/1/0
I could do this with PHP after my select, then go through it and create a separate array, but that seems unnecessary. I find with MySQL there's almost always a query-way to do something.
Use GROUP_CONCAT with GROUP BY
select
b.id 'id',
b.name 'name',
GROUP_CONCAT(t.name) 'tag',
GROUP_CONCAT(t.id) 'tagid'
from
bookTags bt
left join
books b ON b.id = bt.book
left join
tags t ON t.id = bt.tag
GROUP BY bt.book;
Result for your fiddle
+------+------------------+------------------+-------+
| id | name | tag | tagid |
+------+------------------+------------------+-------+
| 1 | 1984 | Government | 2 |
| 2 | Huckelberry Finn | Adventure | 1 |
| 3 | The bible | Religion | 3 |
| 4 | White Fang | Adventure,Nature | 1,4 |
+------+------------------+------------------+-------+
4 rows in set (0.00 sec)
Check
create view booksInfo as
select
b.id 'id',
b.name as 'name',
GROUP_CONCAT(t.name) as 'tag',
GROUP_CONCAT(t.id) 'tagid'
from bookTags bt
left join books b
on b.id = bt.book
left join tags t
on t.id = bt.tag
group by bt.book;
http://sqlfiddle.com/#!2/68cdd/1
You can use the group_concat function to transform a series of values on different rows to a coma delimited values:
SELECT b.id AS book_id, b.name AS book_name,
GROUP_CONCAT(t.name) AS tags,
GROUP_CONCAT(t.id) AS tag_ids
FROM bookTags bt
LEFT JOIN books b ON b.id = bt.book
LEFT JOIN tags t ON t.id = bt.tag
GROUP BY b.id, b.name
GROUP_CONCAT(exp) Function is Dedicated for the comma separated
http://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-group_concat.php
SELECT b.id 'id',b.name 'name',
GROUP_CONCAT(t.name) 'tag',
GROUP_CONCAT(t.id) 'tagid'
FROM
bookTags bt
LEFT JOIN
books b ON (b.id = bt.book)
LEFT JOIN
tags t ON (t.id = bt.tag) GROUP BY bt.book;
You shouldn't manipulate your results in your query. It would be much nicer to return your list with duplicates and roll up on ID.
foreach ($rows as $key => $row) {
$out[$row['id']]['id'] = $row['id'];
$out[$row['id']]['name'] = $row['name'];
$out[$row['id']]['tags'] .= ', '.$row['tags'];
$out[$row['id']]['tagids'] = ', '.$row['name'];
}
This is only quick, but you could roll this up into a nice little function that didn't reference keys directly, didn't repeat commas etc etc etc. (i.e. this is really ugly code and I apologise).
But the moment you try and scale a large amount of data with groups, you'll have another problem to solve.

how to perform select from multiple tables by several ids

i have 3 tables that looks like this:
game_table
+---------+------------+------------+----------------------+----------+
| game_id | game_title | sponser_id | game expiration date | prize_id |
+---------+------------+------------+----------------------+----------+
prize_table
+----------+---------------------------+------------+-------------+--------------------+--------------------------------------------+
| prize_id | prize_image_name | prize_cost | prize_title | remaining_quantity | prize_description |
+----------+---------------------------+------------+-------------+--------------------+--------------------------------------------+
sponser_table
+------------+--------------+
| sponser_id | sponser_name |
+------------+--------------+
how do i build query that select all data from the 3 tables that
meat the statement that go's something like pseudo code:
select all data from game_table and prize_table and sponser_table where game_table.sponser_id = 2 and game_table.prize_id = 2
i tried something like this :
SELECT game_list.*, prize_list.* ,sponser_list.* FROM game_list, prize_list,sponser_list
WHERE game_list.sponser_id=2 And game_list.prize_id = 2 And game_list.game_id=2 ;
but it gave me no good results .
You had a WHERE clause to limit to the correct ids, but you had no join conditions to relate your tables. Instead of the implicit join syntax you attempted (comma-separated table list), use a explicit JOINs with stated relating columns:
SELECT
game_list.*,
prize_list.* ,
sponser_list.*
FROM
game_list
JOIN prize_list ON game_list.prize_id = prize_list.prize_id
JOIN sponser_list ON game_list.sponser_id = sponser_list.sponser_id
WHERE game_list.sponser_id=2 And game_list.prize_id = 2 And game_list.game_id=2 ;
I would recommend against selecting all columns from each table though, since you are duplicating the id columns in at least two places. Instead, be explicit about the columns you want. This will also help you if you later add additional columns to these tables that should not be included in this query.
SELECT
game_id,
game_title,
game_list.sponser_id,
game_expiration_date,
game_list.prize_id,
prize_image_name,
prize_cost,
prize_title,
remaining_quantity,
prize_description,
sponser_name
FROM
game_list
JOIN prize_list ON game_list.prize_id = prize_list.prize_id
JOIN sponser_list ON game_list.sponser_id = sponser_list.sponser_id
WHERE game_list.sponser_id=2 And game_list.prize_id = 2 And game_list.game_id=2 ;
SELECT *
FROM game_table
JOIN prize_table USING (prize_id)
JOIN sponser_table USING (sponser_id)
WHERE sponser_id = 2
AND prize_id = 2
AND game_id = 2
SELECT
game_list.*, prize_list.* ,sponser_list.*
FROM game_list
JOIN prize_list ON game_list.prize_id = prize_list.prize_id
JOIN sponser_list ON game_list.sponser_id = sponser_list.sponser_id
WHERE
game_list.sponser_id=2 And game_list.prize_id = 2 And game_list.game_id=2 ;
From your description it appears that the tables may be related. If they are, you need to use a join, like this:
SELECT *
FROM game_table g
LEFT OUTER JOIN prize_table p ON p.prize_id=g.prize_id
LEFT OUTER JOIN sponser_table s ON s.sponser_id=g.sponser_id
WHERE g.game_id=2

Categories