I have three tables in my database first one is account_group, next is ledger and last one is account_receipt,
account_group has fields group_id and group_name, and this group_id is mapped to ledger, ledger table contains fields ledger_name and group_id. and in the last table account_receipt has fields ledger_id and receipt_amount.
so what I need is I want to get receipt details when group_id is given.I cant write the query for this.any help would be appreciated.
schema::
account_group::
id int(11)
group_name varchar(60)
ledger ::
id int(11)
group_id varchar(60)
ledger_name varchar(60)
account_receipt::
id int(11)
ledger_id int(11)
amount float
receipt_date date
Try the following query. It uses JOINs to connect the various tables, column aliases and table aliases.
SELECT
ag.id group_id,
l.id ledger_id,
l.ledger_name ledger_name
ar.id receipt_id,
ar.amount amount,
ar.receipt_date receipt_date
FROM account_receipt ar
INNER JOIN ledger l ON ar.ledger_id = l.id
INNER JOIN account_group ag ON ag.id = l.group_id AND ag.id = <given group id>;
Three table joining example has been given below
select * from Table_A A
join Table_B B on B.id=A.id
join Table_C C on C.id=A.id
Related
Hi is there a way to join three tables like this but I can't change the reference of the column code.id at the query because I am creating a dynamic query for a search filter for this reference
Here is the code looks like
there are 4 tables bill, expense_distribution, item_distribution, project_code
columns in the bill - id, name, ...etc
columns in the expense_distribution - id, bill_id, project_code_id, ...etc
columns in the item_distribution - id, bill_id, project_code_id, ...etc
columns in the project_code - id, name, ...etc
SELECT b.id, code.name FROM bill b
LEFT JOIN expense_distribution exp ON b.id=exp.bill_id
LEFT JOIN project_code code ON exp.project_code_id=code.id
LEFT JOIN item_distribution itm ON b.id=itm.bill_id
LEFT JOIN project_code code ON itm.project_code_id=code.id
I can't use the query with two times project_code code but I want code.id for both item and expense distributions because of the filter.
can someone guide me for the best approach to do that, I am using JPQL for the code in Java
There are multiple ways to approach this.
One way you can achieve this is by providing different aliases for same table and coalesce the fields.
SELECT b.id, COALESCE(c1.name, c2.name) as name FROM bill b
LEFT JOIN expense_distribution exp ON b.id=exp.bill_id
LEFT JOIN item_distribution itm ON b.id=itm.bill_id
LEFT JOIN project_code c1 ON exp.project_code_id=c1.id
LEFT JOIN project_code c2 ON itm.project_code_id=c2.id;
Another approach would be, change the firsy and last two lines to
SELECT b.id, code.name FROM bill b
LEFT JOIN expense_distribution exp ON b.id=exp.bill_id
LEFT JOIN item_distribution itm ON b.id=itm.bill_id
LEFT JOIN project_code code ON COALESCE(itm.project_code_id, exp.project_code_id)=code.id;
Third, change the last line from above to
LEFT JOIN project_code c1 ON exp.project_code_id=code.id OR itm.project_code_id=code.id
This is the tables creation:
CREATE TABLE bill(
id int(11),
name varchar(10)
);
CREATE TABLE project_code(
id int(11),
name varchar(10)
);
CREATE TABLE expense_distribution(
id int(11),
bill_id int(11),
project_code_id int(11),
name varchar(10)
);
CREATE TABLE item_distribution(
id int(11),
bill_id int(11),
project_code_id int(11),
name varchar(10)
);
Based on these tables you can query the following query:
SELECT b.id, codes.name FROM bill b
LEFT JOIN expense_distribution exp ON b.id=exp.bill_id
LEFT JOIN project_code codes ON exp.project_code_id=codes.id
LEFT JOIN item_distribution itm ON b.id=itm.bill_id and itm.project_code_id =codes.id
I have 6 tables in my database: users, courses, users_courses, lectures, users_lectures and attends. In the headline, I referred to them as A, B, C, D, E and F.
I'm creating an attending system for lecture as a part of my school project and I need to run a query that selects only those lectures where users haven't yet attended.
users table holds information about user. Its' table structure is following:
id INT(10) USINGNED PRIMARY KEY AUTO_INCREMENT
name VARCHAR(255)
email VARCHAR(255)
password VARCHAR(60)
created_at TIMESTAMP
updated_at TIMESTAMP
courses table is a parent table for lectures that holds information about courses where lectures belongs to. Its' table structure is following:
id INT(10) UNSIGNED AUTO_INCREMENT
name VARCHAR(255)
created_at TIMESTAMP
updated_at TIMESTAMP
users_courses is a relationship table between users and courses. It links users to courses. Its' table structure is following:
user_id INT(10) UNSIGNED FOREIGN KEY
course_id INT(10) UNSIGNED FOREIGN KEY
lectures table holds information about upcoming lectures users are supposed to attend. It's table structure is following:
id INT(10)
starting_at DATETIME
ending_at DATETIME
course_id INT(10) UNSIGNED FOREIGN KEY
created_at TIMESTAMP
updated_at TIMESTAMP
users_lectures table is a relationship table between users and lectures. It links lectures to users. Its' table structure is following:
user_id INT(10) UNSIGNED FOREIGN KEY
lecture_id INT(10) UNSIGNED FOREIGN KEY
attends table holds information about attending user's user's id, lecture's id and timestamps for created_at and updated_at. Its' table structure is following:
user_id INT(10) UNSIGNED FOREIGN KEY
lecture_id INT(10) UNSIGNED FOREIGN KEY
created_at TIMESTAMP
updated_at TIMESTAMP
Question:
Is it possible, with one query, to select only those upcoming lectures where users haven't yet attended?
Here's what I've tried, but it doesn't return any rows:
// PHP
$stmt = $pdo->prepare("
SELECT
courses.name AS course,
lectures.id AS id,
lectures.starting_at,
lectures.ending_at,
users.name AS user_name,
users_lectures.user_id
FROM lectures
LEFT JOIN users_courses ON users_courses.course_id = lectures.course_id
LEFT JOIN courses ON courses.id = users_courses.course_id
LEFT JOIN users_lectures ON users_lectures.lecture_id = lectures.id
LEFT JOIN users ON users.id = users_lectures.user_id
LEFT JOIN attends ON attends.lecture_id = users_lectures.lecture_id
WHERE users_lectures.user_id = :user_id
AND lectures.ending_at > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 1 MINUTE)
AND lectures.ending_at > DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 1 MINUTE)
AND attends.lecture_id != users_lectures.lecture_id
AND attends.user_id != :user_id
ORDER BY lectures.starting_at DESC");
Am I missing something or thinking the whole structure in a wrong way?
Sorry for providing such a long text, but I wanted to be as specific as possible. Any help would be much appreciated :)
First of all you need to start with the subject of what you want to return. That would be users. So this will be your first table to select from (Note here: use AS to rename tables for brevity):
Select *
From users AS u
Next link together the data you want. Depending on how specific you want to be will depend on how many joins you will need to make (e.g. courseID vs CourseName).
Now assuming we want lots of human readable data such as names we will link the following tables.
LEFT OUTER JOIN users_lectures AS ul ON u.id = ul.userid
LEFT OUTER JOIN lectures AS l ON l.id = ul.lectureid
LEFT OUTER JOIN courses AS c ON c.id = l.courseid
LEFT OUTER JOIN attends AS a ON a.userid = u.id AND a.lectureid = l.id
And to top it off, to find people who didn't attend, they will not be in the attends table so we just check for people where the values are null for attends.
WHERE a.userid IS NULL
As a side note, you won't get any results with this in the WHERE clause
AND attends.lecture_id != users_lectures.lecture_id
Because you are joining with this statement
LEFT JOIN attends ON attends.lecture_id = users_lectures.lecture_id
Which contradict each other
I have four schemas:
takes(ID,course_id,sec_id,semester,year)
student(ID,name,dept_name,tot_credit)
course(course_id,title,dept_name,credits)
department(dept_name,building,budget)
I want to create a query that finds the name and id of each Astronomy student whose name begins with the letter âTâ and who has not taken at least 16 Astronomy courses.
What's the easiest way I could do this?
I already wrote this beginning bit
SELECT name, id
FROM student
WHERE dept_name='Astronomy' AND name LIKE '%T%'
I'm not quite sure how to finish this off.
Any help would be greatly appreciated :)
Here's the result
NAME ID CLASS_TAKEN
-------------------- ----- -----------
Tolle 38279 12
Teo 62268 13
Tolle 93223 13
Tsukamoto 17707 5
Titi 11576 9
Teo 91772 12
Toraichi 50387 11
Tewari 80754 14
Tiroz 64091 14
9 rows selected
I need Teo with the id 91772 and Tewari 80754 to be gone
Given my reading of the requirements and the comments it's pretty clear that the question is not very clear. :-) What you're looking for are students where (total # of courses given by the Astronomy department) - (# of Astronomy courses taken by student) >= 16. So, how do we find these values? First, let's start with the total number of courses given by the Astronomy department. This is pretty simple:
SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'
Now, the second part is to determine how many courses given by the Astronomy department each student has taken. To do this we need to start with the student, join to the courses the student has taken (the TAKES table), then join to the COURSES table to find out which department each course is part of. Something like the following should do it:
SELECT s.ID, s.NAME, COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY s.ID, s.NAME;
OK, now we need to put this together. You've tagged this question for both Oracle and MySQL so I'm going to guess you'll accept valid syntax for either database; thus I'll use Oracle Common Table Expression syntax to pull everything together:
WITH ASTRONOMY_COURSES AS (SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'),
STUDENT_ASTRO_COURSES AS (SELECT s.ID,
s.NAME,
COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY ID)
SELECT s.ID,
s.NAME,
s.STUDENT_ASTRO_COUNT,
a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT AS UNTAKEN_COUNT
FROM STUDENT_ASTRO_COURSES s
CROSS JOIN ASTRONOMY_COURSES a
WHERE a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT >= 16;
Note here that a CROSS JOIN is used to put together the subqueries. This means that all the rows of each subquery are joined to all the rows of the other subquery - but since in this case the ASTRONOMY_COURSES subquery will only return a single row what we're doing is appending the ASTRONOMY_COURSE_COUNT value onto each row returned by the STUDENT_ASTRO_COURSES subquery.
That should at least get you pretty close. Amend as needed.
Not tested on animals - you'll be first! :-)
Share and enjoy.
Do you need to use all tables?
Table department has no links with the student,
Table takes has no links with the student,
Table coursehas no links with the student.
If student lists total credits that are all Astronomy I think this can be used:
select name, id, MAX(tot_credit) as credits
from student
where dept_name='Astronomy' and name like 'T%'
group by name, id
having MAX(tot_credit)<=16
PS - you schema is not good; PK-FK references are missing
Your query will need to reference more tables than just the student table.
Your tables seem be missing some important information, which student has taken which course. There's a table named takes, but there doesn't appear to be any relationship between takes and student.
So first, figure out how to list the students along with the Astronomy courses they have taken. Each row will identify the student and a course.
SELECT s.id AS student_id
, s.name AS student_name
, t.???
FROM student s
JOIN ??? t
ON t.student_id = s.id
WHERE ...
You may also need to include another "join" to an additional table, in order to identify which course a student has taken is an Astronomy course.
To also include students that have not take any Astronomy courses, you can use an outer join, rather than an inner join. (That would mean including the LEFT keyword before JOIN, and relocating predicates from the WHERE clause to the ON clause. (A predicate in the WHERE clause that can only be satisfied by non-NULL values will negate the outer-ness of the join.)
Once you have a query that returns that set (students along with any astronomy courses they've taken), you can then add a GROUP BY clause to "collapse" a set of rows into a single row. (Looks like you want the rows "grouped" by student.)
And then an aggregate function like COUNT() or SUM() can be used to get a count of rows for each group. (If you don't want to count any re-takes of a course (a "duplicate" course for a student) you may be able to make use of the COUNT(DISTINCT t.foo) form.
And then a HAVING clause can be added to the query, to compare the value returned from the aggregate expression to a constant value, to return only rows that satisfy a specific condition.
FOLLOWUP
Assuming:
CREATE TABLE course
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, title VARCHAR(30) NOT NULL COMMENT 'course title'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, credits DECIMAL(5,2) COMMENT 'credit hours'
, PRIMARY KEY (id)
);
CREATE TABLE student
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, name VARCHAR(30) NOT NULL COMMENT 'student name'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, tot_credit INT COMMENT '?'
, PRIMARY KEY (id)
);
CREATE TABLE takes
( student_id INT UNSIGNED NOT NULL COMMENT 'FK ref student.id'
, course_id INT UNSIGNED NOT NULL COMMENT 'FK ref course.id'
, sec_id INT UNSIGNED NOT NULL COMMENT '?'
, semester INT UNSIGNED NOT NULL COMMENT '?'
, year INT UNSIGNED NOT NULL COMMENT '?'
, PRIMARY KEY (student_id, course_id, sec_id, semester, year)
, CONSTRAINT FK_takes_course FOREIGN KEY (course_id) REFERENCES course (id)
, CONSTRAINT FK_takes_student FOREIGN KEY (student_id) REFERENCES student (id)
);
Query to get a list of students...
SELECT s.id
, s.name
FROM student s
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Get list of students along with the courses they've taken, returning the id of the ASTRONOMY courses they've taken...
SELECT s.id AS student_id
, s.name AS student_name
, c.id AS course_id
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Collapse the rows to one per student using a GROUP BY, and use aggregate functions to get counts or totals.
SELECT s.id AS student_id
, s.name AS student_name
, SUM(c.credits) AS total_astronomy_credits_taken
, COUNT(c.id) AS count_astronomy_courses_taken
, COUNT(DISTINCT c.id) AS count_distinct_astronomy_courses_taken
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
GROUP
BY s.id
, s.name
To omit rows from this resultset, add a HAVING clause. For example, to exclude rows where total_astronomy_credits_taken is greater than or equal to 12...
HAVING total_astronomy_credits_taken >= 12
If you want the rows returned in a certain sequence, specify that in an ORDER BY clause
ORDER BY s.id
If you want to replace NULL values from the aggregates with zeroes, you can warp the aggregate expression in an IFNULL(foo,0) function, e.g.
, IFNULL(COUNT(c.id),0) AS count_astronomy_courses_taken
Try this :
select a.name, a.id, count(b.ID) as class_taken
from student a inner join takes b
on a.ID = b.ID
inner join course c
on b.course_id = c.course_id
where a.dept_name='Astronomy' and substring(a.name,1,1) = 'T'
group by a.name, a.id
having count(b.ID) < 17
I'm not even sure of the correct terminology here. MySQL newbie, more or less.
Given a couple tables defined as follows:
CREATE TABLE users
( user_id int(11) NOT NULL auto_increment
, name VARCHAR(255)
, pri_location_id mediumint(8)
, sec_location_id mediumint(8)
, PRIMARY KEY (user_id)
);
CREATE TABLE locations
( location_id mediumint(8) NOT NULL AUTO_INCREMENT
, name varchar(255)
, PRIMARY KEY (location_id)
)
I'm trying to do a query to get the user name and both primary and secondary locations in one go.
I can get one like this:
SELECT u.name AS user_name, l.name as primary_location FROM users u, locations l WHERE u.primary_location_id=l.location_id
But I'm drawing a total blank on the correct syntax to use to get both in one query.
SELECT u.name AS user_name, l1.name as primary_location , l2.name as secondary_location
FROM users u
JOIN locations l1 ON(u.pri_location_id=l1.location_id)
JOIN locations l2 ON(u.sec_location_id = l2.location_id);
First of, I would strongly consider changing your DB schema if allowable to add a users_locations table that can be used to properly describe this many to many relationship.
This table could look like:
user_id location_id location_type
1 1 primary
1 2 secondary
2 1 secondary
2 2 primary
and so forth.
You would likely want a compound primary key across all three columns. And location_type might best be enum data type.
Your query would then be like
SELECT
u.name AS user_name
l.name AS location_name
ul.location_type AS location_type
FROM users AS u
INNER JOIN user_location AS ul /* possibly use left join here if user can exist without a location */
ON u.user_id = ul.user_id
INNER JOIN locations AS l
ON ul.location_id = l.location_id
ORDER BY ul.location_type ASC
This would return up to two records per user (separate record for primary and secondary, primary listed first)
If you need this collapsed to a single record you could do this:
SELECT
u.name AS user_name
COALESCE(CASE WHEN ul.location_type = 'primary' THEN l.name ELSE NULL END CASE) AS primary_location,
COALESCE(CASE WHEN ul.location_type = 'secondary' THEN l.name ELSE NULL END CASE) AS secondary_location
FROM users AS u
INNER JOIN user_location AS ul /* possibly use left join here if user can exist without a location */
ON u.user_id = ul.user_id
INNER JOIN locations AS l
ON ul.location_id = l.location_id
GROUP BY `user_name`
If however you are stuck with current schema, then solution by #Jlil should work for you.
i have 3 tables:
users:
uid int(11) - userid(primary key, auto_increment)
name varchar(255)
pass varchar(64)
created int(11)
projects:
pid int(11) .....
name varchar(150)
description varchar(255)
created int(11)
users_projects:
uid int(11) - user id
pid int(11) - product id
What is the query for: showing the projects(name and description) sorted by name for the user with a certain name?
This is what i've got so far:
SEECT name,description FROM projects ORDER BY name ASC
SELECT a.*, b.*
FROM users a
INNER JOIN users_projects b
ON a.uid = b.uid
INNER JOIN projects c
ON b.pid = c.pid
ORDER BY a.Name ASC
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Looks like you just need to join up the tables. Here #Name is a parameter containing the user's name you want project details for:
SELECT projects.Name,
projects.Description
FROM projects
INNER JOIN users_projects
ON projects.pid = users_projects.pid
INNER JOIN Users
ON users_projects.UId = Users.UId
WHERE Users.Name = #Name
ORDER BY projects.Name ASC