I have the following tables
1. tblJobs
JobID int primary key
JobTypeID int
JobClientID int
JobStaffID int
....
2. tblContacts
ContactID int primary key
ContactName varchar
....
3. tblJobTypes
TypeID int primary key
TypeName varchar
I can SELECT data from these table with this SQL...
SELECT tblContacts.ContactName, tblContacts.ContactID,
tblJobs.JobID, tblJobs.JobTypeID, tblJobs.JobClientID, tblJobs.JobStaffID,
tblJobTypes.* FROM (tblJobs LEFT JOIN tblJobTypes ON tblJobs.JobTypeID = tblJobTypes.TypeID) LEFT JOIN tblContacts ON tblJobs.JobClientID = tblContacts.ContactID;
An example row from the SQL...
| ContactName| ContactID | JobID | JobTypeID | JobClientID | JobStaffID |TypeID | TypeName |
| Mr Contact | 290 | 341 | 3 | 290 | 202 | 3 | Enquiry |
As you can see this SQL joins the tblJobs.JobClientID to tblContacts.ContactID(290).
This is how I get tblContacts.JobStaffID (202).
How can I modify the SQL to get tblContacts.ContactName?
I've tried joining tables twice but with no success.
Assuming that JobStaffID is a foreign key relating to tblContacts.ContactID you're correct in assuming that you need to join the tblContacts table twice - but you have to give it different aliases in each join like this:
SELECT
c1.ContactName as ClientName, c1.ContactID as ClientID,
c2.ContactName as StaffName, c2.ContactID as StaffID,
j.JobID, j.JobTypeID, j.JobClientID, j.JobStaffID,
jt.TypeID, jt.TypeName
FROM tblJobs j
LEFT JOIN tblJobTypes jt ON j.JobTypeID = jt.TypeID
LEFT JOIN tblContacts c1 ON j.JobClientID = c1.ContactID
LEFT JOIN tblContacts c2 ON j.JobStaffID = c2.ContactID;
And while at it you might want to use aliases for all tables to reduce the query text.
Related
I have a database with two tables one table (shops) has an admin user column and the other a user with less privileges. I plan to LEFT JOIN the table of the user with less privileges. When I retrieve the data, the records for the admin user must be on a separate row and must have NULL values for the left joined table followed by records of users with less privileges (records of the left joined table) if any. I am using MySQL.
I have looked into the UNION commands but I don't think it can help. Please see the results bellow of what I need.
Thank you.
SELECT *
FROM shops LEFT JOIN users USING(shop_id)
WHERE shop_id = 1 AND (admin_id = 1 OR user_id = 1);
+---------+----------+---------+
| shop_id | admin_id | user_id |
+---------+----------+---------+
| 1 | 1 | NULL | <-- Need this one extra record
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 1 | 1 | 3 |
+---------+----------+---------+
Here is an example structure of the databases and some sample data:
CREATE SCHEMA test DEFAULT CHARACTER SET utf8 ;
USE test;
CREATE TABLE admin(
admin_id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(admin_id)
);
CREATE TABLE shops(
shop_id INT NOT NULL AUTO_INCREMENT,
admin_id INT NOT NULL,
PRIMARY KEY(shop_id),
CONSTRAINT fk_shop_admin FOREIGN KEY(admin_id) REFERENCES admin (admin_id)
);
CREATE TABLE users(
user_id INT NOT NULL AUTO_INCREMENT,
shop_id INT NOT NULL,
CONSTRAINT fk_user_shop FOREIGN KEY(shop_id) REFERENCES admin (shop_id)
);
-- Sample data
INSERT INTO admin() VALUES ();
INSERT INTO shops(admin_id) VALUES (1);
INSERT INTO users(shop_id) VALUES (1),(1),(1);
I think you need union all:
select s.shop_id, s.admin_id, null as user_id
from shops s
where s.shop_id = 1
union all
select s.shop_id, s.admin_id, u.user_id
from shops s join
users u
on s.shop_id = u.shop_id
where shop_id = 1;
Put your where condition in On clause
SELECT *
FROM shops LEFT JOIN users on shops.shop_id=users.shop_id and (admin_id = 1 OR user_id = 1)
WHERE shops.shop_id = 1
This query:
SELECT contacts.name, accounts.account
FROM contacts
LEFT JOIN deals
ON contacts.id = deals.contact_id
LEFT JOIN
accounts ON accounts.deal_id = deals.id;
returns:
+------+-------------------+
| name | account |
+------+-------------------+
| Bob | fun deal account |
| Bob | NULL |
| John | NULL |
+------+-------------------+
But I expected:
+------+-------------------+
| name | account |
+------+-------------------+
| Bob | fun deal account |
| Bob | fun deal account |
| John | NULL |
+------+-------------------+
The first LEFT JOIN behaves correctly. Since there are two deals for Bob, Bob correctly shows up twice in result set. But the second LEFT JOIN does not behave right, because the account should have been carried over twice for both Bob records, but instead there is a NULL for the second bob.
The schema:
CREATE TABLE contacts(
id int AUTO_INCREMENT,
name VARCHAR(50),
Primary Key(id)
)
INSERT INTO contacts VALUES('Bob');
INSERT INTO contacts(name) VALUES('John');
CREATE TABLE deals(
id int AUTO_INCREMENT,
name VARCHAR(20),
contact_id int,
FOREIGN KEY(contact_id) REFERENCES contacts(id),
Primary Key(id)
);
INSERT INTO deals(name, contact_id) VALUES('cool deal',1);
INSERT INTO deals(name, contact_id) VALUES('another cool deal',1);
CREATE TABLE accounts(
id int AUTO_INCREMENT,
account VARCHAR(50),
deal_id int,
FOREIGN KEY(deal_id) REFERENCES deals(id),
PRIMARY KEY (id)
)
INSERT INTO accounts(account, deal_id) VALUES('fun deal account', 1);
Why doesn't the second LEFT JOIN give desired behavior and how can I get the 'fun deal account' account to show up for both Bobs?
Bob have two deals but deals.id is auto_increment so fun deal account only match the first row in deals table, the cool deal.
You need to add INSERT INTO accounts(account, deal_id) VALUES('fun deal account', 2); too
In case of doubts, decompose your query.
The first LEFT JOIN could be this:
SELECT contacts.id as contact_id, contacts.name, deals.id as deals_id, deals.name
FROM contacts
LEFT JOIN deals ON contacts.id = deals.contact_id
Which results in :
contact_id name deals_id name
1 Bob 1 cool deal
1 Bob 2 another cool deal
2 John NULL NULL
The second LEFT JOIN is:
LEFT JOIN accounts ON accounts.deal_id = deals.id
So the result given is logical given your data, you have only one account with deal_id=1 so it matches the first row where deals.id=1 : "cool deal" .
I think your mistake is on the last part of your query, the query you wanted is :
SELECT contacts.name, accounts.account FROM contacts LEFT JOIN deals ON contacts.id = deals.contact_id LEFT JOIN accounts ON accounts.deal_id = deals.contact_id
"accounts.deal_id = deals.contact_id" instead of "accounts.deal_id = deals.id" is the deal (pun intended) to have your expected result.
I've these 3 tables:
___Invoices:
|--------|---------------|
| INV_Id | IVC_BookingId |
|--------|---------------|
| 10 | 31 |
|--------|---------------|
___Bookings:
|--------|-------------|---------------|---------------|
| BOO_Id | BOO_GuestId | BOO_CompanyId | BOO_BillingId |
|--------|-------------|---------------|---------------|
| 10 | 89 90 | 0 |
|--------|-------------|---------------|---------------|
___Kardex:
|--------|----------|-------------|-------------|
| KDX_Id | KDX_Type | KDX_Name | KDX_Company |
|--------|----------|-------------|-------------|
| 89 | guest | Frank | |
| 90 | company | | Google |
|--------|----------|-------------|-------------|
I would like to find for an Invoice the linked card user.
For example, for INV_Id = 10, it should return me:
|--------|-------|---------|---------|
| INV_Id | guest | company | billing |
|--------|-------|---------|---------|
| 10 | Frank | Google | 0 |
|--------|-------|---------|---------|
billing is actually empty because I do not have any existing like between my invoice and booking and kardex.
So my try is the following:
SELECT IVC_Id, IVC_BookingId, IFNULL(BOO_GuestId, 0) AS BOO_GuestId, IFNULL(BOO_CompanyId, 0) AS BOO_CompanyId, IFNULL(BOO_BillingId, 0) AS BOO_BillingId, KDX_Name, KDX_Company
FROM ___Invoices
JOIN ___Bookings
ON ___Bookings.BOO_Id = ___Invoices.IVC_BookingId
LEFT JOIN ___Kardex
ON ___Kardex.KDX_Id = ___Bookings.BOO_BillingId
WHERE IVC_Id='10'
I've no error but I can get the name or company from the ___Kardex table.
Do you know why please ?
Here the SQL Fiddle: http://sqlfiddle.com/#!9/211d01/1
Thanks.
I'm not too sure about your relationships or foreign keys. But from what you have given, I think this would do. Might need slight modifications, but I guess you will get the idea.
SELECT ___Invoices.IVC_Id, k1.KDX_Name as guest, k2.KDX_Company as company
FROM ___Invoices
JOIN ___Bookings
ON ___Bookings.BOO_Id = ___Invoices.IVC_BookingId
LEFT JOIN ___Kardex k1 ON ___Bookings.BOO_GuestId = k1.KDX_Id
LEFT JOIN ___Kardex k2 ON ___Bookings.BOO_CompanyId = k2.KDX_Id
WHERE ___Invoices.IVC_Id='10'
Please check this and let me know if it's what you wanted.
http://sqlfiddle.com/#!9/211d01/31
Feel free to ask if you have any doubts. Hope it helps :)
Please check your second JOIN query:
LEFT JOIN ___Kardex
ON ___Kardex.KDX_Id = ___Bookings.BOO_BillingId
It should be
LEFT JOIN ___Kardex
ON ___Kardex.KDX_Id = ___Bookings.BOO_CompanyId
SQL Fiddle: http://sqlfiddle.com/#!9/211d01/7
You are joining to __Kardex on a BillingID of 0.
0 Does not equal 89 or 90
Your code
LEFT JOIN ___Kardex
ON ___Kardex.KDX_Id = ___Bookings.BOO_BillingId
Here is how I solved: I joined to the same table twice with a different join criteria each time. And then created a new alias for that join:
CREATE TABLE `inv` (`INV_ID` VARCHAR(255) NOT NULL, `IVC_BookingID`
VARCHAR(255) NOT NULL);
CREATE TABLE `bookings` (`BOO_id` VARCHAR(255) NOT NULL, `BOO_guestid` VARCHAR(255) NOT NULL, `BOO_CompanyID` VARCHAR(255) NOT NULL, `BOO_BillingID` VARCHAR(255) NOT NULL);
CREATE TABLE `kardex` (`KDX_ID` VARCHAR(255) NOT NULL, `KDX_TYPE` VARCHAR(255) NOT NULL, `KDX_NAME` VARCHAR(255) NOT NULL, `KDX_COMPANY` VARCHAR(255) NOT NULL);
INSERT INTO `inv` (INV_ID,IVC_BookingID) SELECT '10','31';
INSERT INTO `bookings` (BOO_id,BOO_guestid,BOO_CompanyID,BOO_BillingID) SELECT '10','89','90','0';
INSERT INTO `kardex` (KDX_ID,KDX_TYPE,KDX_NAME,KDX_COMPANY) SELECT '89','guest','Frank','';
INSERT INTO `kardex` (KDX_ID,KDX_TYPE,KDX_NAME,KDX_COMPANY) SELECT '90','company','','Google';
SELECT a.INV_ID, c.kdx_name, d.kdx_company FROM inv a
INNER JOIN bookings b ON b.boo_id=a.INV_ID
INNER JOIN kardex c ON c.kdx_id=b.boo_guestid
INNER JOIN kardex d ON d.kdx_id=b.BOO_CompanyID
WHERE INV_ID='10';
RESULT
INV_ID kdx_name kdx_company
10 Frank Google
You can try
SELECT IVC_Id,
(SELECT KDX_Name FROM ___Kardex WHERE KDX_Id= ___Bookings.BOO_GuestId) AS guest,
(SELECT KDX_Company FROM ___Kardex WHERE KDX_Id= ___Bookings.BOO_CompanyId) AS company,
___Bookings.BOO_BillingId as billing
FROM ___Invoices
JOIN ___Bookings
ON ___Bookings.BOO_Id = ___Invoices.IVC_BookingId
WHERE IVC_Id='10'
It probably not the most optimal solution if your concern is performance, but in you schema design you should not have one table handling more then one type of information, this makes it difficult to write any legit joins.
i have a mysql table promotions main fields are
PromotionMaintenanceID (Primary)
PID
PromotionID
PromotionName
I have a special case where the PromotionID of one record (This will be the main Record) become the PID of some of some other records. I need to create a MySql statement to get record with PromotionMaintenanceID (of main Record) , PromotionID (of main Record) , PromotionName (of main Record) and PromotionID of all the records which has PID =PromotionID of the main record
PromotionMaintenanceID ,PID , PromotionID ,PromotionName
1 | T1 | 12 | Promo1
2 | 12 | 22 | PromoSub
3 | 12 | 33 | PromoSub2
I need my result like
PromotionMaintenanceID | PID | PromotionID | PromotionName | Sub PromoID
1 | T1 | 12 | Promo1 |22,33
Any one know how the query should be?
This query (SQLFiddle) should do what you want:
SELECT p1.PromotionMaintenanceID, p1.PID, p1.PromotionID, p1.PromotionName, GROUP_CONCAT(p2.PromotionID) AS `Sub PromoID`
FROM promotions p1
JOIN promotions p2
ON p2.PID = p1.PromotionID
GROUP BY p1.PromotionID
Output:
PromotionMaintenanceID PID PromotionID PromotionName Sub PromoID
1 T1 12 Promo1 33,22
For that you should be able to do a straight join (or double select depending on your favourite way)
SELECT
a.PromotionID,
a.MaintenanceId,
a.PromotionName,
GROUP_CONCAT(b.PID) as SubIds
FROM
PromotionTable a
LEFT JOIN
PromotionTable b
ON
a.PromotionID = b.PID
//ADD AND's here with a.(column) = b.PID if you absolutely need all the ID's for each column to link up
GROUP BY
a.PromotionID, a.MaintenanceID, a.PromotionName
I've got the following table layouts:
Table Data
+----------+-------------------------+
| Field | Type |
+----------+-------------------------+
| type | enum('type_b','type_a') |
| type_id | int(11) unsigned |
| data | bigint(20) unsigned |
+----------+-------------------------+
Table A and B:
+--------------+------------------+
| Field | Type |
+--------------+------------------+
| id | int(11) unsigned |
| customer_id | int(11) unsigned |
| ... |
+--------------+------------------+
In table Data there is some messurement data from a certain type (a or b).
Now I want for ever customer the total sum for both types of data a and b.
So, I thought: select the sum, join on a or b and group by a.customer_id, b.customer_id.
Resulting in the following query:
SELECT sum(d.data) as total
FROM data d, ta, tb
WHERE
(d.type LIKE "type_a" AND d.type_id = ta.id)
OR
(d.type LIKE "type_b" AND d.type_id = tb.id)
GROUP BY ta.customer_id, tb.customer_id;
This doesn't get me the proper results...
I tried several approaches, left joins, joining on the customer table and group by customer.id etc. Does anyone have a clue what I'm doing wrong?
Thanx!
Your query
SELECT sum(d.data) as total
FROM data d, ta, tb
WHERE
(d.type LIKE "type_a" AND d.type_id = ta.id)
OR
(d.type LIKE "type_b" AND d.type_id = tb.id)
GROUP BY a.customer_id, b.customer_id;
Let's say there is only one record in d, and it is type_a. There are two records in ta and tb each. The record in d matches one of the records in ta on d.type_id=ta.id. Therefore, that combination of (d x ta) allows ANY tb record to remain in the final result. You get an unintended cartesian product.
SELECT x.customer_id, SUM(data) total
FROM
(
SELECT ta.customer_id, d.data
FROM data d JOIN ta
ON (d.type LIKE "type_a" AND d.type_id = ta.id)
UNION ALL
SELECT tb.customer_id, d.data
FROM data d JOIN tb
ON (d.type LIKE "type_b" AND d.type_id = tb.id)
) X
GROUP BY x.customer_id;