Select two items from a table as two different things - mysql

I have two tables: tblOrganisations and tblContacts. I have a query that brings back Organisations. I also want to bring back two contacts of different types (primary=1, alternate=2) linked to an organisation. However, I'm stuck on how to bring back multiple fields, for multiple contacts, from one table as different things.
So far I can get their ReferenceID's as PrimaryID and SecondaryID.
SELECT tblOrganisations.*
, ( SELECT tblContacts.ReferenceID
FROM tblContacts
WHERE tblOrganisations.ReferenceID = tblContacts.tblOrganisations_ReferenceID
AND tblContacts.tblContactTypes_ReferenceID = 1
) AS PrimaryID
, ( SELECT tblContacts.ReferenceID
FROM tblContacts
WHERE tblOrganisations.ReferenceID = tblContacts.tblOrganisations_ReferenceID
AND tblContacts.tblContactTypes_ReferenceID = 2
) AS SecondaryID
FROM tblOrganisations
The above query gets me the organisation, and the ReferenceID's of their contacts from tblContacts as PrimaryID and SecondaryID for the two different types of contact I want. But I want more fields for each contact - FirstName, LastName, EmailAddress etc
I tried stuff like;
SELECT tblOrganisations.*
,
( SELECT tblContacts.ReferenceID AS PrimaryID ,
FirstName AS PrimaryFirstName
FROM tblContacts
WHERE tblOrganisations.ReferenceID = tblContacts.tblOrganisations_ReferenceID
AND tblContacts.tblContactTypes_ReferenceID = 1
)
,
( SELECT tblContacts.ReferenceID AS SecondaryID ,
FirstName AS SecondaryFirstName
FROM tblContacts
WHERE tblOrganisations.ReferenceID = tblContacts.tblOrganisations_ReferenceID
AND tblContacts.tblContactTypes_ReferenceID = 2
)
FROM tblOrganisations
But that doesn't actually bring back anything in PrimaryID, SecondaryID, PrimaryFirstName etc
Thanks for any help or pointers :)

The table with the desired values has to be joined twice.In this case it would be tblcontacts.
SELECT
o.*,
c1.referenceid AS PrimaryID,c1.firstname as primaryfirstname,
c2.referenceid AS SecondaryID,c2.firstname as secondaryfirstname
FROM tblOrganisations o
JOIN tblContacts c1 on o.ReferenceID = c1.tblOrganisations_ReferenceID
JOIN tblContacts c2 on o.ReferenceID = c2.tblOrganisations_ReferenceID
WHERE c1.tblContactTypes_ReferenceID = 1 and c2.tblContactTypes_ReferenceID = 2

Related

Join 2 tables and display by id,priority & number

Example tables and desired result:
The result table shown below is the output I actually want.
tried the following query with pivot:
with pivot_data AS
(
select client_id
,ph_type
,Ph_number
from client_table
inner join phone_table
on client_table.phone_id = phone_table.ph_id
)
select *
from pivot_data
pivot (sum(ph_number)
for ph_type in ('c','w','h')
);
Result I got:
Any help would be appreciated.
Answers in sql server would be great but oracle & mysql is also welcome if they can point me in the right direction. :)
Thanks in advance.
Oracle Query:
SELECT *
FROM (
SELECT client_id, priority, phone_number, phone_type
FROM client_table c
LEFT OUTER JOIN
phone_table p
ON ( c.phone_id = p.phone_id )
)
PIVOT ( MAX( phone_type ) AS phonetype, MAX( phone_number ) AS phonenumber
FOR priority IN ( 1 AS Prio1, 2 AS Prio2, 3 AS Prio3 ) );
Output:
CLIENT_ID PRIO1_PHONETYPE PRIO1_PHONENUMBER PRIO2_PHONETYPE PRIO2_PHONENUMBER PRIO3_PHONETYPE PRIO3_PHONENUMBER
---------- --------------- ----------------- --------------- ----------------- --------------- -----------------
1 C 9999999999 H 5555555555 W 7777777777
You really need to do some reading on set based thinking and how what you are asking for will be very detrimental to your maintenance of the SSIS solution moving forwards.
All you need to do is export the data as is. If you absolutely have to have it all in the one CSV file, just join the two tables together and retain a normalised, scalable dataset that won't break if the number of priorities increases:
select c.client_id
,c.phone_id
,c.priority
,p.phone_type
,p.phone_number
from #Client c
join #Phone p
on c.phone_id = p.phone_id

mysql SELECT EXISTS on multiple tables

Have tables: person,person_ip
Both tables have pid column as a primary key, in table person there is column state_id, in table person_ip there is column ip.
Want to discover if specified IP address is assigned to person with state_id is not equal to 2. But always got result 1, even if state_id is 0, 1 or 2. Always got 0 only if ip address is not listed at all. What am I doing wrong?
SELECT EXISTS (
SELECT person_ip.PID
FROM person_ip,person
WHERE person.PID=person_ip.PID
AND person.state_id NOT IN (2)
AND person_ip.ip='10.11.12.13'
)
this seems like a simple join.. unless i'm missing something
select person.*
from person
inner join person_ip
on person.pid = person_ip.pid
where person.state_id <> 2
and person_ip.ip_address = '10.0.0.1'
If you want to exclude the ip_address if it has been assigned to any user with state = 2, even if it has also been assigned to a user without state = 2, then try:
select max(i)
from (
select *
from (
select 1 as i
from dual
where not exists (
select 1
from person p
inner join person_ip pi
on p.pid = pi.pid
where p.state_id = 2
and pi.ip_address = '10.0.0.1'
)
) q
union
select 0
) qq
(dual is a system table that can be used as a sort of stub table)
here's a fiddle showing both versions
update after some actual sleep
Okay, so the above query is a little.. out there. Back in the real world, this one is probably more appropriate:
select count(case when p1.state_id = 2 then 1 end)
from person p1
inner join person_ip pi1
on p1.pid = pi1.pid
where pi1.ip_address = '10.0.0.1'
group by pi1.ip_address;
This will return 1 or more if your ip_address has been used by someone with a state_id of 2, and 0 if it has never been used by someone with a state_id of 2.
It will return nothing if the ip has never been used.
this fiddle has all three of the above queries.
SELECT IF(COUNT(*)>0,1,0)
FROM person
INNER JOIN person_ip
ON person.pid = person_ip.pid
AND person_ip.ip_address = '10.0.0.1'
WHERE person.state_id <> 2

MySQL Complicated Contacts Table

I am trying to output a list of contact names with their phone number and email address for a given company.
The problem I am facing is getting it to output a contact based on the following criteria:
Contacts may or may not have a name, email or telephone, but they must have at least one of these to appear in the results.
There can be more than one contact per company.
There can be more than one email address and/or telephone number per contact.
There is a primary flag on contacts, so if there is more than one contact and one of them is primary, it should pick that one instead of the other non-primary one.
I have tried the following for getting the contacts name but with no success:
SELECT entity_details.name,
COALESCE(
(SELECT entity_contacts.name FROM entity_contacts
WHERE entity_contacts.entityRef = entity_details.id
ORDER BY entity_contacts.isPrimary = 1),
(SELECT entity_contacts.name FROM entity_contacts
WHERE entity_contacts.entityRef = entity_details.id)
)
AS contact
FROM entity_details
WHERE entity_details.ownerRef = ?
This is the closest thing I can get to but I am unsure of if it's correct or not, and it doesn't prioritise primary contacts, it just selects any and groups on the entityRef to remove duplicates:
SELECT
entity_details.name, entity_contacts.name AS contact,
entity_contacts_telephones.tel, entity_contacts_emails.email
FROM entity_details
LEFT JOIN entity_contacts ON entity_details.id = entity_contacts.entityRef
LEFT JOIN entity_contacts_telephones ON entity_contacts.id = entity_contacts_telephones.contactRef
LEFT JOIN entity_contacts_emails ON entity_contacts.id = entity_contacts_emails.contactRef
WHERE entity_details.ownerRef = ?
GROUP BY entity_contacts.entityRef
LIMIT ?, ?
All tables are Innobd, the ones I am working with are in the above edit. All references etc have indexes on where nesisary.
In entity_details there around about 13000 rows, 12000 in entity_contacts, and a few 1000 in entity_contacts_telephones and entity_contacts_emails.
I thought the following would work but it doesn't:
LEFT JOIN entity_contacts_telephones
ON entity_contacts.id = entity_contacts_telephones.contactRef
AND COALESCE(entity_contacts_telephones.isPrimary = 1, 0)
This may work (not sure mainly because it's not clear how many rows per entity you can have in each table):
SELECT
entity_details.name,
( SELECT entity_contacts.name
FROM entity_contacts
WHERE entity_contacts.entityRef = entity_details.id
ORDER BY entity_contacts.isPrimary DESC
LIMIT 1
) AS contact
FROM entity_details
WHERE entity_details.ownerRef = ?
You probably need a join - of the [greatest-n-per-group] type:
SELECT
d.name,
...
c.whatever
...
FROM
entity_details AS d
JOIN
entity_contacts AS c
ON c.PK = --- the PRIMARY KEY of contacts table
( SELECT cc.PK
FROM entity_contacts AS cc
WHERE cc.entityRef = d.id
ORDER BY cc.isPrimary DESC
LIMIT 1
)
WHERE d.ownerRef = ?
An index on (entityRef, isPrimary) would help improving peformance.

Subscribe between fields In sql

i have a table with these fields
id,cid,cv
with these data
1,5,code
2,3,code4
3,3,cod2
1,4,code5
1,3,code4
] want select id what cid=5 and cv=code and cid=3 or 4 and cv=code4.
I expect that id=1.
I used this query,but result is 0
SELECT id FROM table WHERE (cid='5' and cv='code') and (cid in ('3','4') and cv='code4')
sorry for bad english.
SELECT id FROM my_table
WHERE (cid=5 and cv='code')
or ((cid = 3 and cv='code4')
and (cid = 4 and cv='code4'))
group by id
SQL Fiddle Example
Try this (change the AND between the parenteses to OR):
SELECT id
FROM table
WHERE (cid='5' and cv='code') OR (cid in ('3','4') and cv='code4')
You should try using ORs instead of ANDs
SELECT id
FROM table
WHERE (cid='5' and cv='code')
OR (cid in ('3','4') and cv='code4')
I put this at http://sqlfiddle.com/#!2/40054/51 (you can tell by the last number being 51 I took some wrong turns). I think this is called "Key Value," I proposed an edit to the tags for this post, but I think you should re-tag it to include key-value. Anyway: databases like this are difficult to query compared to approaches where one row refers to one thing - instead you have one row referring to one attribute. So if you want to know something about what "things" have certain attributes, you have to paste the attributes for each thing together in one row. Run the query below and you'll see what I mean:
SELECT laptops.laptop, rams.termvalue as ramCount,
cpus.termvalue as cpusCount,
maker.termvalue as company
FROM (SELECT DISTINCT laptop FROM my_table) As Laptops
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'ram') AS rams
ON rams.laptop = laptops.laptop
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'cpu') AS cpus
ON cpus.laptop = laptops.laptop
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'company') AS maker
ON maker.laptop = laptops.laptop
If you put up other questions about this type of database, you should always mention that you're using a "key/value" arrangement, it's uncommon and not what any of us assumed.
In your fiddler example you wanted to find company = dell and cpu = 2 or ram = 2, so you would query that whole query by wrapping it in parentheses and giving it an alias, like this:
SELECT * FROM (
SELECT laptops.laptop, rams.termvalue as ramCount,
cpus.termvalue as cpusCount,
maker.termvalue as company
FROM (SELECT DISTINCT laptop FROM my_table) As Laptops
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'ram') AS rams
ON rams.laptop = laptops.laptop
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'cpu') AS cpus
ON cpus.laptop = laptops.laptop
LEFT JOIN (SELECT laptop, termvalue FROM my_table
WHERE term = 'company') AS maker
ON maker.laptop = laptops.laptop
) as laps
WHERE company = 'dell' AND (cpuscount = 2 OR ramcount = 2)

How do you do multiple inserts that have selects

How do I do an insert multiple values or records that have to get their information from select statements. This doesn't work.
INSERT INTO marriedcouples (male,female) VALUES (
(SELECT id FROM men WHERE username='brad',
SELECT id FROM women WHERE username='jennifer')
(SELECT id FROM men WHERE username='ken',
SELECT id FROM women WHERE username='barbie'))
Assuming I have tables with:
men(id,name), women(id,name), couples(id,male,female)
etc.
Thanks,
Dan
Insert marriedcouples( male, female )
Select M.id, W.id
From Men As M
Cross Join Women As W
Where ( M.username = 'brad' And W.username = 'jennifer' )
Or ( M.username = 'ken' And W.username = 'barbie' )
Addition
In comments, you asked specifically about the problems with your original query. First, you could have used your original approach like so:
Insert marriedcouples( male, female )
Select ( Select Id From men Where username = 'brad' )
, ( Select Id From women Where username = 'jennifer' )
Union All
Select ( Select Id From men Where username = 'ken' )
, ( Select Id From women Where username = 'barbie' )
Notice that each value is enclosed in parentheses as its own encapsulated subquery. Second, notice that I used the Union All directive to allow me to stack the two queries and give me two rows. Third, notice that I'm not trying to use the Values directive in combination with subqueries. You can use the Values clause to list out values or you can use a Select statement but not both in the way you did. Obviously, this approach of four subqueries will not perform well but it helps to understand the breakdown of the syntax.