Not unique table/alias error in SQL - mysql

When trying to run I get the error "Not unique table/alias: 'Caller'", im not sure what it means but i feel like it has something to do with joining the same two tables twice on different values
SELECT Company_name,Contact_id, COUNT(Company_name) as nc
FROM Customer
JOIN Caller ON Customer.Company_ref = Caller.Company_ref
JOIN Caller ON Customer.Contact_id = Caller.Caller_id
JOIN Issue ON Caller.Caller_id = Issue.Caller_id
GROUP by Company_name, Contact_id
HAVING COUNT(Company_name) < 5

if you are using the same table call it another name or both tables to have different names... in this case to avoid confusion let A and B.
SELECT Company_name,Contact_id, COUNT(Company_name) as nc
FROM Customer
JOIN Caller A ON Customer.Company_ref = A.Company_ref
JOIN Caller B ON Customer.Contact_id = B.Caller_id
JOIN Issue ON A.Caller_id = B.Caller_id
GROUP by Company_name, Contact_id
HAVING COUNT(Company_name) < 5

You need to qualify your column names. I can guess:
SELECT c.Company_name, c.Contact_id, COUNT(*) as nc
FROM Customer JOIN
Caller co
ON co.Company_ref = c.Company_ref JOIN
Caller ca
ON c.Contact_id = ca.Caller_id JOIN
Issue i
ON ca.Caller_id = i.Caller_id
GROUP by c.Company_name, c.Contact_id
HAVING COUNT(*) < 5;
Whenever you have multiple tables in a query, you should use table aliases and qualified table names.
Without seeing the data, I'm not sure if this does anything useful. The two joins to the same table on different keys are suspicious.

Related

How is joining with a subquery different from joining without a subquery? Looking for difference between two similar queries

I want to see which user created floor equipment for which customer -- both of these queries do what I want. The second query, however, results with 700 more rows than the first. Could you please explain the difference?
I ran another query that found the difference between the two sets -- sure enough, this query yielded 700 rows. Therefore, the data output is the same, but somehow the second query catches more results. I tried looking at the additional 700 rows, but they all seemed normal and similar to the other results. I can't find the difference by looking at the code, which is what I'm hoping someone can help me with
First query
SELECT customer.name, user.name, floor_equipment.id
FROM customer, user, floor_equipment, floor, building, site
WHERE (floor_equipment.floorID = floor.ID AND floor.buildingID = building.id AND
building.siteID = site.id AND floor_equipment.created_by = user.id)
Second Query
SELECT newTable.custName, newTable.userName, newTable.equipID
FROM (SELECT customer.name as "custName", user.name as "userName",
floor_equipment.id as "equipID", floor_equipment.created_by as "creatorID"
FROM customer, floor_equipment, floor, building, site
WHERE (floor_equipment.floorID = floor.ID AND floor.buildingID = building.id AND
building.siteID = site.id AND site.customerID = customer.ID)) as newTable, user
WHERE user.id = newTable.creatorID
I would expect both of these queries to have the same result, however the second query yields 700 more rows than the first. Aside from the extra rows, both queries result in the same data. The 700 additional rows seem to be normal and similar to the other rows.
NOTE: There is a seemingly pointless subquery in the second query. The purpose of this was for optimization. I am running these queries within Domo, a business intelligence webapp. I wrote the subquery in hopes that it would run faster. Because of the way Domo works, the former took 2 hours whereas the latter took 45 seconds.
Ignoring (or perhaps rectifying) the syntax errors, your first query can be written as follows:
SELECT c.name
, u.name
, fe.id
FROM customer c
CROSS
JOIN user u
JOIN floor_equipment fe
ON fe.created_by = u.id
JOIN floor f
ON f.ID = fe.floorID
JOIN building b
ON b.id = f.buildingID
JOIN site s
ON s.id = b.siteID
Likewise, written a little more coherently, your second query is as follows:
SELECT x.custName
, x.userName
, x.equipID
FROM
( SELECT c.name custName
, u.name userName
, fe.id equipID
, fe.created_by creatorID
FROM customer c
JOIN site s
ON s.customerID = c.ID
JOIN building b
ON b.siteID = s.id
JOIN floor f
ON f.buildingID = b.id
JOIN floor_equipment fe
ON fe.floorID = f.ID
) x
JOIN user u
ON u.id = x.creatorID
Again, we can omit the subquery and write it thus...
SELECT c.name custName
, u.name userName
, fe.id equipID
, fe.created_by creatorID
FROM customer c
JOIN site s
ON s.customerID = c.ID
JOIN building b
ON b.siteID = s.id
JOIN floor f
ON f.buildingID = b.id
JOIN floor_equipment fe
ON fe.floorID = f.ID
JOIN user u
ON u.id = fe.created_by
...so we can see that the first query had a cartesian product (CROSS JOIN), whereas the second query does not.
Your code is a Cartesian product between the tables:
customer, user, floor_equipment, floor, building, site
and your where condition is not for a join but just for a tuple of Boolean value
floor_equipment.floorID = floor.ID,
floor.buildingID = building.id,
building.siteID = site.id,
floor_equipment.created_by = user.id
( boolean, boolean, boolean, boolean)
each boolean is the result for the corresponding match eg:
floor_equipment.floorID = floor.ID
so practically return all the rows because have not matching counterpart.
In the second, your first Cartesian product is expanded by the join between the first result and the matching rows for user.id and newTable.creatorID. Looking to your code, it could be that you need an explicit join syntax and proper on condition.

SQL query to select values from a table where the condition is from related tables

I'm struggling to write a SELECT query in my PHP application. The situation is following:
I have table ADDRESS with one-to-many relation to table CONTEST. The relation is via junction table ContestHasAddress. CONTEST table has many-to-many relation to DATE table via junction table ContestHasDate.
I was trying to SELECT all columns from ADDRESS table WHERE the column1 from DATE related to its CONTEST (who is related to the ADDRESS) is bigger then a specific VALUE. I have attached the linke below showing the relation view from phpmyadmin.
I tried that but it was a failure
SELECT address.*
FROM address,
contest,
date
WHERE address.contest.dates[0].start_time > TIMESTAMPVALUE
You need to use JOINs to establish all of the table relations to get to the Date table. Then, you can compare the values:
Select A.*
From Address A
Join Contest_Has_Address CA On A.Id = CA.Address_Id
Join Contest C On C.Id = CA.Contest_Id
Join Contest_Has_Date CD On C.Id = CD.Contest_Id
Join Date D On D.Id = CD.Date_Id
Where D.Start_Time > TIMESTAMPVALUE
You need to join the tables using the "junction table". I have assumed that Startime is DateTime field and not Int.
Select address.* from Address inner join ContestHasAddress
on Address.ID = Contest_Has_Address.address_ID INNER JOIN
Contest_Has_Date on Contest_Has_Address.ContestID = Contest_Has_Date.contestID
inner join date on Contest_Has_Date.DateId = Date.ID
where StartTime > TIMESTAMPVALUE

Very slow sql query for count

I need get report count for each user role, but my sql query very slow (40 sec on good server). My sql query:
SELECT `auth_assignment`.`item_name`, COUNT(*) as count
FROM `report`
LEFT JOIN `company` ON company.id = report.company_id
LEFT JOIN `auth_assignment`
ON auth_assignment.user_id = company.user_id
GROUP BY `auth_assignment`.`item_name`
ORDER BY `count`
auth_assignment.item_name is role type.
auth_assignment has ~23k rows.
company ~11k rows.
reports ~12k rows (one company can have many reports).
report.id and company.id, have binding
First, you are aggregating on a column from the third table in a left join. I'm guessing you don't want NULL for the value, so use inner join or change the order of the tables.
Table aliases make the query easier to write and to read:
SELECT aa.item_name, COUNT(*) as cnt
FROM report r JOIN
company c
ON c.id = r.company_id JOIN
auth_assignment aa
ON aa.user_id = c.user_id
GROUP BY aa.item_name
ORDER BY cnt;
Assuming the join's are correct for the tables, then you just want to be sure that you have indexes. These should go on the columns used for the joins: company(id, user_id), auth_assignment(user_id, item_name).

More Efficient Version of this Correlated Subquery

I've got 3 different tables and I need to pull data once from 2 of them, and twice from the third. The tables are jobs, customers, and customers_attributes. I'm trying to pull data for a specific job, and part of that data is information about the customer who owns the job. Customer data is stored in customers_attributes where the type of data is defined as an integer that corresponds with a type(using strings here for simplicity's sake) and then a content field contains the data itself.
In this case, I need to pull 2 rows from the customers_attributes table that correspond to the customer that corresponds to the job. One row for 'PhoneNumber', and another row for 'CustomerInfo'. I used an INNER JOIN for one of them, but because I can't put WHERE values for both, I used a subquery for the other one. I think this is really nasty and I'm sure there's got to be a cleaner way of doing it:
SELECT jobs.*, customers.Name AS CustomerName,
customers_attributes.Content AS PhoneNumber,
( SELECT `Content`
FROM customers_attributes
WHERE Type = 'CustomerInfo' AND ForeignCustomer = jobs.Customer
LIMIT 1) AS CustomerInfo
FROM jobs
INNER JOIN customers ON jobs.Customer = customers.ID
INNER JOIN customers_attributes ON jobs.Customer = customers_attributes.ForeignCustomer
WHERE jobs.ID = $jobID AND customers_attributes.Type = 'PhoneNumber'
LIMIT 1
I should mention that a customer could have multiple rows for the same attribute if they have more than 1 job, and this query ideally should either return the latest information, or the information that was submitted at the same time as the job(based on corresponding ID orders).
Just join the same table again under a different alias.
SELECT j.*, c.Name AS CustomerName,
ca.Content AS PhoneNumber,
ca2.Content as CustomerInfo
FROM jobs j
INNER JOIN customers c ON j.Customer = c.ID
INNER JOIN customers_attributes ca ON (j.Customer = ca.ForeignCustomer)
INNER JOIN customers_attributes ca2 ON (j.Customer = ca2.ForeignCustomer)
WHERE j.ID = '$jobID'
AND ca.Type = 'PhoneNumber'
AND ca2.Type = 'CustomerInfo'
LIMIT 1
Warning
It looks like you're using PHP. If you must insist on using the outdated mysql_ library and not the much improved mysqli_ lib.
Please remember to use mysql_real_escape_string() and to quote your $vars.
If not you'll be hid by SQL-injection problems.

Crossing MySQL Tables

I feel like this is something I can search for, but I don't know the correct terminology to go about it.
I have a SQL database that has a a few tables. One table stores caller logs for a softphone (agent_log), one table stores campaign information for what the people on the softphone are calling on (campaigns). Both tables have the column "campaign_id" that I can use to call to each other (I think). I need to relate these two tables so that I can have a sql query that would look like
SELECT * FROM agent_log WHERE active = 'Y';
Obviously it doesn't work because the column 'active' doesn't exist in that table, it exists in the campaigns table. Is there any simple way to go about this?
What you are trying to do is called a JOIN You would JOIN the tables using a field that is common between them, so for your tables it would be campaign_id.
SELECT *
FROM agent_log al
INNER JOIN campaigns c
ON al.campaign_id = c.campaign_id
WHERE c.active = 'Y'
OR
SELECT *
FROM agent_log al
INNER JOIN campaigns c
ON al.campaign_id = c.campaign_id
AND c.active = 'Y'
I suggest you do some reading about JOINs. The Visual Explanation of Joins is a great start.
id campaign_id exists in both table and assuming that there is a relation between table you can join them:
SELECT agent_log.campaign_id
FROM agent_log, campaigns
WHERE agent_log.campaign_id = campaigns.campaign_id
AND campaigns.active = 'Y'
if you like to use JOIN i suggest you spend some of your time to learn it.
SELECT *
FROM agent_log
INNER JOIN campaigns ON agent_log.campaign_id = campaigns.campaign_id
WHERE campaigns.active = 'Y';
You simply need to use a JOIN query like this
SELECT al.*
FROM agent_log as al
INNER JOIN campaigns as c
ON al.campaign_id = c.campaign_id
WHERE c.active = 'Y';
You need to make sure you have indexed on campaign_id field on both tables and the active field in the campaign table to make the query run efficiently.
This should work without inner join
SELECT
agent_log.campaign_id
FROM
agent_log,
campaigns
WHERE
agent_log.campaign_id = campaigns.campaign_id
AND
campaigns.active = 'Y';