Joining two tables with reference to foreign key - mysql

I have some problems with joining two tables when foreign key is no set directly.
I have two tables:
TABLE A
{A.ID} {A.NAME} {Parentid} {A_FK} (foreign key)
A.ID1 A.NAME1 NULL A_FK1
A.ID2 A.NAME2 NULL A_FK2
A.ID3 A.NAME3 A.ID2 NULL
A.ID4 A.NAME4 NULL A.FK4
OtherA OtherId Other Other
Table B
{B.ID} {B.Code}
A.FK1 some_text1
A.FK2 some_text2
A.FK4 some_text3
B.ID1 some_text4
In table A. A.ID3 does not have FK but it has ParentID that point to A.ID2 which has ForeingKey.
I would like to have expected:
{A.ID} {A.NAME} {B.Code}
A.ID1 A.NAME1 some_text1
A.ID2 A.NAME2 some_text2
A.ID3 A.NAME3 some_text2
A.ID4 A.NAME4 some_text3
Can anyone help me with this join?

If your parent-child relationship can be of multiple levels, then you need to write a recursive query something like this:
CREATE TABLE TableA(ID INT, Name VARCHAR(10), ParentID INT NULL, FK INT NULL );
CREATE TABLE TableB( ID INT, Code VARCHAR(50));
INSERT INTO TableA VALUES (1, 'Name1', NULL, 1);
INSERT INTO TableA VALUES (2, 'Name2', NULL, 2);
INSERT INTO TableA VALUES (3, 'Name3', 2, NULL);
INSERT INTO TableA VALUES (4, 'Name4', NULL, 4);
INSERT INTO TableA VALUES (5, 'Name4', 3, NULL);
INSERT INTO TableB VALUES (1, 'Some Text 1');
INSERT INTO TableB VALUES (2, 'Some Text 2');
INSERT INTO TableB VALUES (4, 'Some Text 3');
WITH X (ID, NAME, FK) AS (
SELECT ID, NAME, FK
FROM TABLEA
WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID, T.NAME, X.FK
FROM TABLEA T
INNER JOIN X ON (T.PARENTID = X.ID)
)
SELECT X.ID, X.NAME , TABLEB.CODE
FROM X INNER JOIN TABLEB ON (X.FK = TABLEB.ID);

You could first get all rows to be joined on TableB using FK and UNION ALL them with rows to be joined on TableA using ParentID:
SAMPLE DATA
CREATE TABLE TableA(
ID INT,
Name VARCHAR(10),
ParentID INT NULL,
FK INT NULL
)
CREATE TABLE TableB(
ID INT,
Code VARCHAR(50)
)
INSERT INTO TableA VALUES
(1, 'Name1', NULL, 1),
(2, 'Name2', NULL, 2),
(3, 'Name3', 2, NULL),
(4, 'Name4', NULL, 4);
INSERT INTO TableB VALUES
(1, 'Some Text 1'),
(2, 'Some Text 2'),
(4, 'Some Text 3');
QUERY
SELECT
a.ID, a.Name, b.Code
FROM TableA a
INNER JOIN TableB b ON a.FK = b.ID
WHERE a.ParentID IS NULL
UNION ALL
SELECT
a1.ID, a1.Name, b.Code
FROM TableA a1
INNER JOIN TableA a2 ON a2.ID = a1.ParentID
INNER JOIN TableB b ON a2.FK = b.ID
WHERE a1.FK IS NULL
ORDER BY ID
RESULT
ID Name Code
----------- ---------- -------------------
1 Name1 Some Text 1
2 Name2 Some Text 2
3 Name3 Some Text 2
4 Name4 Some Text 3

Try this code , this is working correctly
SELECT TABLEA.ID,TABLEA.NAME,TABLEB.Code
FROM TABLEA
INNER JOIN TABLEB
ON TABLEA.ID=TABLEB.ID OR TABLEA.Parentid=TABLEB.ID;

Related

Order 2 tables by the same field in each table, mysql, classic asp

I am trying to order data from 2 tables to display in one list also based on the id's from a third table.
Table 3 contains ID's to the other 2 tables.
e_allocation table
------------------
eid, sid, iid
5, 1234, NULL
5, NULL, 1234
table 1 and 2 are tables of similar data.
i_status table
--------------
iid, status
1234, Complete
1235, Complete
1236, Not Complete
s_status table
--------------
sid, status
1234, Complete
1235, Not Complete
1237, Not Complete
objCon.Execute ("SELECT a.sid, a.iid, b.status AS istats, c.status AS sstats
FROM e_allocation a LEFT JOIN i_status b ON a.iid=b.iid LEFT JOIN s_status c
ON a.sid=c.sid WHERE a.eid = '5' ORDER BY b.status Desc, c.status Desc")
So Currently I can get the data from the database but it obviously orders table b first and then c second. I need these ordered as joined.
Currently returning (Table=I or S, Record ID=1234, Status = Complete or Not Complete):
I:1234:Complete
I:1235:Complete
I:1236:Not complete
S:1234:Complete
S:1235:Not Complete
S:1237:Not Complete
I'm trying to get:
I:1234:Complete
S:1234:Complete
I:1235:Complete
S:1235:Not Complete
I:1236:Not complete
S:1237:Not Complete
while not objDb.EOF
sid = objDb("id")
iid = objDb("iid")
if sid <>"" then datlst = datlst &"S:"& sid &":"&objDb("sstats")&",<BR>"
if iid <>"" then datlst = datlst &"I:"& iid &":"&objDb("istats")&",<BR>"
objDb.MoveNext
Wend
response.write datlst
Any pointers in the right direction greatly appreciated?
Thanks
Here's my attempt.
create table e_allocation (eid int, sid int, iid int);
insert into e_allocation select 5, 1234, NULL;
insert into e_allocation select 5, NULL, 1234;
insert into e_allocation select 5, 1235, NULL;
insert into e_allocation select 5, NULL, 1235;
insert into e_allocation select 5, 1236, NULL;
insert into e_allocation select 5, NULL, 1236;
create table i_status (iid int, status varchar(25));
insert into i_status select 1234, 'Complete';
insert into i_status select 1235, 'Complete';
insert into i_status select 1236, 'Not Complete';
create table s_status (sid int, status varchar(25));
insert into s_status select 1234, 'Complete';
insert into s_status select 1235, 'Not Complete';
insert into s_status select 1237, 'Not Complete';
SELECT
case when a.sid is null then 'I' else 'S' end as iors,
ifnull(a.sid,a.iid) as id,
ifnull(b.status,c.status) as status
FROM e_allocation a LEFT JOIN i_status b ON a.iid=b.iid LEFT JOIN s_status c
ON a.sid=c.sid
WHERE a.eid = '5' and (b.status is not null or c.status is not null)
ORDER BY id, iors
Another time please do provide the CREATE TABLE etc. statements so we don't have to type them in.

How to find the column having duplicate value in SQL Server

I have a table:
create table #t
(
ID int,
value nvarchar(5)
)
insert #t
values (1,'A'), (2, 'B'), (3, 'A'), (3, 'B')
Sample data:
ID value
------------
1 A
2 B
3 A
3 B
For my project I need the ID which has having both the values
Result :
ID
3
Kindly help me out.
To get IDs having 2 values
select id
from #t
group by id
having count(distinct value) >= 2
or to get all IDs having A and B
select id
from #t
where value in ('A','B')
group by id
having count(distinct value) = 2
or to make it more generic to get IDs having all values
select id
from #t
group by id
having count(distinct value) = (select count(distinct value) from #t)

MYSQL - Updating count in one tabled based on two other tables joined

I have 3 related tables. Adults, Children and AC. Adults contains an INT column to count high school seniors. Children contains a column with year of highs school graduation. AC links the adult.id to the children.id.
CREATE TABLE adults (
id INT,
name VARCHAR(10),
seniors INT DEFAULT 0
) ;
INSERT INTO adults (id, name) VALUES
(1, 'adam'),
(2, 'bob');
CREATE TABLE children (
id INT,
name VARCHAR(10),
grad VARCHAR(4)
) ;
INSERT INTO children (id, name, grad) VALUES
(1, 'sally', '2016'),
(2, 'johnny', '2017'),
(3, 'eric', '2016'),
(4, 'billy', '2016'),
(5, 'rachel', '2016');
CREATE TABLE pc (
id INT,
a_id INT,
c_id INT
) ;
INSERT INTO pc (id, a_id, c_id) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 2, 3),
(5, 2, 2);
SQLFiddle: http://sqlfiddle.com/#!2/89281e
So I want to update adults.seniors to the count of '2016' children they're linked to. So adult #1 would be "2" (sally and eric), and adult #2 "1" (eric).
The real data will be run across 25,000+ children being matched up to 40,000+ parents with a row count on the "pc" table above 3,000,000 rows - so looking for efficiency. I started working down this path but a) it's not working for obvious reasons and b) I doubt it would be efficient...
UPDATE adults a SET
seniors = (
SELECT p.a_id, count(*)
FROM pc p
INNER JOIN children c ON c.id = p.c_id
WHERE c.grad = '2016'
GROUP BY p.c_id)
WHERE p.a_id = a.id;
I'm thinking there has to be a better way of doing this with joins but can't seem to wrap my head around it.
You should be looking for this update statement:
UPDATE adults a
JOIN
(SELECT
p.a_id, COUNT(*) childrencount
FROM
pc p
INNER JOIN children c ON c.id = p.c_id
WHERE
c.grad = '2016'
GROUP BY p.a_id) c ON (a.id = c.a_id)
SET
seniors = c.childrencount;

MySql get status of all records from associative table

Given the following DataBase:
CREATE TABLE album ( id int );
INSERT INTO album (id) VALUES
(1),
(2),
(3),
(4);
CREATE TABLE icon_album ( albumID int, current int );
INSERT INTO icon_album (albumID, current) VALUES
(1, 1),
(1, 1),
(2, 1),
(2, 0),
(3, 0),
(3, 0);
I would like to get the following result
albums: id status
1 1
2 0
3 0
4 0
What is the MySql query that would give me the correct result?
P.S. 1: This is my second question for this problem. This first question did not yield a working solution
Is this what you're looking for?
SELECT a.id, IF(i.current IS NULL, 0, current) AS status
FROM album a LEFT JOIN
(
SELECT albumID, MIN(current) AS current
FROM icon_album
GROUP BY albumID
) i ON a.id = i.albumID
Try Like this
"SELECT albumID AS id, if(SUM(current)>1,1,0) AS status FROM icon_album GROUP BY albumID"

Select columns other than the one specified in GROUP BY clause

Is there a way to select columns other the one specified in the group by clause?
Let's say I have the following schema:
Student(id, name, age), Course(id, name, credit), Enrollment(student_id, course_id, grade)
I want to query for each course the following: course's name, student_count.
I came up with workaround, but I was wondering if there's a cleaner way to do this:
SELECT MAX(c.name), COUNT(distinct e.student_id)
FROM Enrollment e
INNER JOIN Course c ON c.id = e.course_id
GROUP BY e.course_id;
You might want to copy this DDL, adjust it to match your schema, and paste it into your question.
create table Student(
student_id integer primary key,
student_name varchar(35) not null,
age int not null default 20
);
create table Course(
course_id integer primary key,
course_name varchar(35) not null,
credit integer not null default 3
);
create table Enrollment(
student_id integer not null references Student (student_id),
course_id integer not null references Course (course_id),
primary key (student_id, course_id),
grade char(1) not null
);
insert into student values
(1, 'a', 20),
(2, 'b', 20),
(3, 'c', 20);
insert into course values
(1, 'course 1', 3),
(2, 'course 2', 3),
(3, 'course 3', 3);
insert into enrollment values
(1, 1, 'b'),
(2, 1, 'b'),
(3, 1, 'b'),
(1, 2, 'b'),
(2, 2, 'b'),
(3, 3, 'b');
Now, you can get the number of students enrolled in each course by querying only the "enrollment" table.
select course_id, count(student_id) num_students
from enrollment
group by course_id
order by course_id;
course_id num_students
--
1 3
2 2
3 1
All that remains is to get the corresponding course name. To do that, you just join the table "Course" with the query we just wrote.
select course.course_name, course_enrollment.num_students
from course
inner join (select course_id, count(student_id) num_students
from enrollment
group by course_id) course_enrollment
on course.course_id = course_enrollment.course_id;
course_name num_students
--
course 1 3
course 3 1
course 2 2
No, you can't. But you can extend GROUP BY with c.name:
SELECT MAX(c.name), COUNT(distinct e.student_id)
FROM Enrollment e
INNER JOIN Course c ON c.id = e.course_id
GROUP BY e.course_id, c.name
Because e.course_id is unique, it won't change results.