Getting data from 2 tables with relationship with WHERE clausule - php

I've been following the PHP Authentication Tutorial en managed to get it working.
Now I want to add a function to my navbar. I will try to explain and hopefully someone has the answer.
I have the 2 user tables, users and user_permissions.
In the user table there are additional columns named district_id, district, gemeente_id and gemeente. I also have 2 extra tables in the database called districten and gemeenten.
The districten table has 2 colums. id and district which holds the unique ID and the name. The gemeente table has at least these 3 columns id, district_id and gemeente.
Here is what I would like to happen:
When the user logs in the query will give a result in an <ul> in the navbar where it will show all values (column gemeente) from the gemeenten table where the user has been assigned to.
Example:
User ZZZ is assigned to district A.
This district holds 4 gemeenten : City 1, City 2, City 3 and City 4
When the user logs in, he should
only see the cities from the District A.
I don't know how to get this working in Slim2 Framework and integrated in the PHP Authentication code. So any help is much appreciated.

First you have to normalize your table and get rid of redundant information since it's hard to maintain it in relational database(I assume here you're using relational database like MySQL).
So basically each user is assigned to gemeente, each gemeente assigned to district and district in his turn has cities(gemeenten). In user table you only need the gemeente_id. The schema of districten and gemeente seems fine.
There are two way how to retrieve needed data: by running 2 queries(1 for fetch user's district; 2nd for fetch district's cities) and run everything in one query. Which way to choose is up to you.
1st approach:
SELECT d.id FROM district AS d LEFT JOIN gemeente AS g ON g.district_id=d.id LEFT JOIN user AS u ON u.gemeente_id=g.id WHERE u.id=<user_id>
SELECT g.id, g.gemeenten from gemeente as g where g.district_id = <res_of_prev_query>
2nd approach:
SELECT
g.id, g.gemeenten
FROM gemeente AS g
LEFT JOIN
districten AS d
ON g.district_id=d.id
INNER JOIN (
SELECT DISTINCT district_id, u.id AS user_id
FROM gemeente as gg
INNER JOIN user AS u
ON u.gemeente_id=gg.id) AS ud
ON ud.district_id=g.district_id
WHERE ud.user_id=<user_id>
You need transform this query to your ORM/ActiveRecord, run it and display the ul list
UPD: I've updated my answer. Thanks #DarkBee for pointing me to my mistake

Related

How to SELECT SQL data using the results from a previous SELECT

Lets guess I have 3 tables:
Table a where I have a name and email
Table b where I have a text and user (as a reference to email from table a)
Table c where I have follower and following (both references to email in table a)
Im trying to develop a simple html/php/sql web that allows me to register many users and let them post different texts while also having the chance to follow or be followed by other users (already done) and I want to give an user the possibility to display the texts from table b that he himself posted and those from the users he is following
Im seriously struggling with how to extract this information
SELECT b.text
FROM tableB as b
LEFT JOIN tableC as c
ON b.user = c.follower
WHERE b.user = "currentuser"
This is as far as I got, which only shows the texts posted by the user himself (something I can do way more simple) but I cant seem to understand how to get those from the users he is following
I hope its understandable without any photo
You first want to find all following users in table c rows where the current user is the follower. Then you want to add the current user (or alternatively always have all users follow themselves). Then you want to find all texts for those users.
So:
select b.text
from (
select following as user
from tableC
where follower="current user"
union
select "current user"
) show_users
join tableB as b on b.user=show_users.user
or if you have a tableC row where follower=following for all users, just:
select b.text
from tableC as c
join tableB as b on b.user=c.following
where c.follower="current user"

Retrieving management hierarchy report from db

I need to prepare report that returns for each of our employee complete list of their higher ups.
I have two mariadb tables: employee and position
employee:
id, name, first_boss_id, position_id,
position:
id, position_name
Employee table contains all employees from juniors to top managers, but every entry contains only name of employee and his closest boss in hierarchy. How can I get all of the managers above him? I've got this so far:
SELECT e.id, e.name, p.position_name, b.name,
FROM employee e
LEFT JOIN employee b ON e.firts_boss_id = b.id
LEFT JOIN position p ON e.position_id = p.id
It returns id, name of employee, his carrier position and name of his closest manager/boss. How can I get names of the rest of higher management for this employee? Is it better to use SQL query or write some PHP script to create that report from data I get from query above?
Either way I could really use some pointers how to get it done. Thank you!

MySQL - structuring query to discard common results

That title is really not useful, but its a complex question (in my head, maybe) ... anywho...
Say I have a MySQL table of Countries (A-Z all countries in the world) with id & name
Then I have a table where I am tracking which countries a user has been to: Like so:
Country Table
id name
1 india
2 luxembourg
3 usa
Visited Table
id user_id country_id
1 1 1
2 1 3
Now here's what I want to do, when I present the form to add to the list of visited countries I want country.id 1 & 3 to be excluded from the query result.
I know I can filter this using PHP ... which is something I have done in the past ... but surely there must be a way to structure a query in such a way that 1 & 3 are excluded from the returned results, like:
SELECT *
FROM `countries`
WHERE `id`!= "SELECT `country_id`
FROM `visited`
WHERE `user_id`='1'"
I suspect it has something to do with JOIN statements but I can't quite figure it out.
Bonus gratitude if someone can point me in the right direction with Laravel.
Thanks you all :)
Is this what you want?
select c.*
from countries c left join
visited v
on c.id = v.country_id and v.user_id = 1
where v.country_id is null;
You can also express this as a not in or not exists, but the left join method typically has pretty good performance.
The left outer join keeps all records in the first table regardless of whether or not the on clause evaluates to true. If there are no matches in the second table, then the columns are populated with NULL values. The where clause simply chooses these records -- the ones that do not match.
Here is another way of expressing this that you might find easier to follow:
select c.*
from countries c
where not exists (select 1 from visited where c.id = v.country_id and v.user_id = 1)
You can use your query like this.
SELECT *
FROM `countries` c LEFT JOIN `visited` v on c.id = v.country_id
WHERE v.`country_id` is null
AND v.`user_id` = 1
This is a operation of a LEFT JOIN. What is means is that I'm selecting all registries from the table countries that may or may not is on the table visited based on the ID of the country.
So it will bring you this group
from country from visited
1 1
2 no registry
3 3
So on the where condition (v.country_id is null) I'm saying: I only want the ones that on this left join operation is only on the country table but it is not on visited table so it brings me the id 2. Plus the condition that says that those registries on visited must be from the user_id=1
SELECT * FROM COUNTRIES LEFT JOIN
VISITED ON
countries.id = visited.country_id and visited.country_id NOT IN ( SELECT country_id FROM visited )
if i understand right maybe you need something like this ?

Mysql Query Relations M-M Table

I'm having a small problem making a query in MySQL.
I have the following tables:
member;
group;
member_has_group (this one has the columns id_group referes to the group id and id_member referes to member id)
I'm trying to make a query that gives me the members from a selected group. Can you help me?
I'm not familiar with join tables, but for the search i made i think thats probably one of the solutions.
Thanks in advance.
Elkas
If you know the group id
select member.* from member m
inner join member_has_group mg on m.id = mg.id_member
where mg.id_group = [x]
If you only know the group name
select member.* from member m
inner join member_has_group mg on m.id = mg.id_member
inner join group g on g.id = mg.id_group
where g.name = 'group name'
This is trival in SQL :
SELECT m.id_member, m.name
FROM member AS m
INNER JOIN member_has_group AS h ON (m.id_member=h.id_member)
WHERE (h.id_group=#my_id_group)
#my_id_group is the group id you have to give.
Yep, you need a join here.
SELECT *
FROM `member`
JOIN `group` ON member.id = group.id
JOIN `member_has_group` ON group.id = member_has_group.id
Depending on the information in your tables, you may not need the third table at all.You only need a connector table with you have a "many to many" relationship between then.
(Ignore the rest if you already know
about database normalization)
For example, if you had two tables, Authors and Books. Authors would contain fields such as Name, Publisher, Birthday, whatever is a property of the "author". Books would contain relevant "book" information. This is a "one-to-many" relationship. An author may be linked (via a field such as author_id) to several books, but a book can only have one author. You would not need a third table here.
Building on that, say you had a third table for "Character Names". This would be a list of main character names used in any of the books in the "Books" table. One of the characters happens to be named John Steele. John has a whole series of books written about him. In the Books table, several of the books may list John Steele as a character. While in the characters table, John Steele could be listed in several books. This is "many-to-many". You need a third table here. It would only have two fields. A book_id and character_id, one entry for each book that John Steele appears in.
MySql Manual on DB Normalization

Join SQL tables

Suppose that in table "ab" I have the names of the students that get along from class "a" and class "b", identically I have table "ac" and "bc". What SQL query should I use in order to get all the combinations possible of students who can form groups (i.e. "get along together")? And how can i extend this to n classes?
For example: John from class a gets along with Jen from class b and Steff from class c, and Jen and Steff get along. Therefore John, Jen and Steff can form a group).
For this I would create two tables, a student table (id, name, class) and a relationship table (student1, student2). You might also want to add a class table for the time, location etc of the class.
A friendship would have two relationships (2,3) and (3,2) to describe it as two way. One way might be a follower or fan of another student.
This will scale up to a lot more than 3 classes.
Then you can use multiple joins to get friends of friends and so on to an arbitrary depth.
Here is a query to get friends of friends (fof):
SELECT fof_details.*
FROM relationships r
INNER JOIN relationships fof
ON r.student2 = fof.student1
INNER JOIN student fof_details
ON fof_details.id = fof.student2
WHERE r.student1 = '12';
There are also database engines made specifically for doing graph modeling like this.
http://openquery.com/blog/graph-engine-mkii
This query should return all students who can be in one group with John.
WITH ABC AS (SELECT AB.A, AB.B, AC.C FROM (SELECT * FROM AB
INNER JOIN BC
ON AB.B=BC.B)
INNER JOIN AC
ON (AC.C=BC.C AND AB.A=AC.A))
SELECT STUDENT FROM (
SELECT AB.B STUDENT FROM ABC WHERE AB.A='John'
UNION
SELECT AC.C STUDENT FROM ABC WHERE AB.A='John')
GROUP BY STUDENT
PS.: Written fast without any syntax check, hope you'll be able to bring this to work :)
The initial query can be satisfied by the code
select ab.a, ab.b, ac.c
from
ab inner join
bc on ab.b = bc.b inner join
ac on ac.a = ab.a and bc.c = ac.c
Stepping up to n classes will get progressively more complex as n=4 would be the same query with the additional three joins
inner join ad on ab.a = ad.a
inner join bd on bd.b = ab.b and ad.d = bd.d
inner join cd on cd.c = ac.c and ad.d = cd.d
2 classes requires 1 table and no joins,
3 classes requires 3 tables and 2 joins,
4 classes requires 6 tables and 5 joins
So we can see it getting progressively more complex as we proceed
First you don't want to have a table for each class. You are capturing the same type of information in multiple tables and this is generally considered a bad practice. You want to "normalize" your data so that the same data exists in one place.
Second, name your tables appropriately so that you understand what you are actually trying to build. Maybe you are generalizing to mask what your intentions for the actual implementations are by using "ab" in the question, but if you are doing this in your actual code it will hurt you in the long run.
It appears you need a people table with names and a friends table where you track who is friends with who:
create table people ( id int, name char(128) );
create table friends ( id int, person_id int, friend_id int );
Then you just need to have the query to get the groups:
SELECT person.* FROM friends
INNER JOIN friends grp
ON friends.friend_id = grp.person_id
INNER JOIN people person
ON person.id = grp.friend_id
WHERE friends.person_id = 42;

Categories