I couldnt find this, i'm sure its simple.
Table (196 rows)
tech, name, area, manager
------------------------------
Joe,mary,pa,sally
Kim,brad,ga,tim
kelly,Joe,pa,sally
Joe,jose,pa,sally
a tech is assigned to multiple name/area/managers. I want to do a report that shows all the rows of the table with a column showing the number of assignments for the tech.
My desired results
tech, name, area, manager, (count of number of tech assignments)
Joe,mary,pa,sally,2
Kim,brad,ga,tim,1
kelly,Joe,pa,sally,1
Joe,jose,pa,sally,2
I'm guessing you want a subquery on the SELECT clause:
SELECT
name,
area,
manager,
(SELECT COUNT(*) FROM tablename WHERE tech = x.tech) AS assignments
FROM tablename x
And here is a possibly more efficient way to do the same thing:
SELECT
t.name,
t.area,
t.manager,
sub.assignments
FROM tablename t
INNER JOIN (
SELECT tech, COUNT(*) AS assignments
FROM tablename
GROUP BY tech
) sub
ON sub.tech = t.tech
select
a.tech, a.name, a.area, a.manager,
b.cnt
from table a, (
select count(*) cnt, tech
from table
group by tech) b
where a.tech=b.tech;
Is this what you want?
SELECT tech, count(name) AS total_records FROM db_table GROUP BY tech
Not sure this is what you're looking for though.
Oh yeah, looks like you really need to use subquery.
Thanks for the examples, that helped.
SELECT tech, name, area, manager, assignments
FROM table
INNER JOIN (
SELECT tech, COUNT(*) AS assignments
FROM table
GROUP BY tech
) t
USING (tech)
Explanation:
Select all columns from table and join them with table containing tech column and count of rows from table having particular tech. Keyword USING says how those two table merge.
Related
I encountered a problem on a database I am working with. I have a table of counsels which may hold repeating values, but their is an enrolment number filed which is unique and can be used to fetch them. However, I want to join from a cases_counsel table on the "first" unique value of the counsel table that matches that column on the cases counsel table.
I want to list the cases belonging to a particular counsel using the enrolment_number as the counsel_id on the cp_cases_counsel table. That means I want to pick just a distinct value of a counsel, then use it to join the cp_cases_counsel table and also return the count for such.
However, I keep getting duplicates. This was the mysql query I tried
SELECT T.suitno, T.counsel_id, COUNT(*) as total from cp_cases_counsel T
INNER JOIN (SELECT
enrolment_number as id, MIN(counsel)
FROM
cp_counsel
GROUP BY
enrolment_number
) A
ON A.id = T.counsel_id
GROUP BY T.suitno, T.counsel_id
and
SELECT enrolment_number as id, MIN(counsel) as counsel, COUNT(*) as total FROM cp_counsel
JOIN cp_cases_counsel ON cp_cases_counsel.counsel_id = cp_counsel.enrolment_number
GROUP BY enrolment_number
For the second query, it's joining twice and I am having like double of what I am supposed to get.
The columns that you want in the results are councel (actually only one of all its values) from cp_counsel and counsel_id from cp_cases_counsel, so you must group by them and select them:
SELECT a.counsel, t.counsel_id, COUNT(*) AS total
FROM cp_cases_counsel t
INNER JOIN (
SELECT enrolment_number, MIN(counsel) AS counsel
FROM cp_counsel
GROUP BY enrolment_number
) a ON a.enrolment_number = t.counsel_id
GROUP BY a.counsel, t.counsel_id;
I have the following SQL Database structure:
Users are the registered users. Maps are like circuits or race tracks. When a user is driving a time a new time record will be created including the userId, mapId and the time needed to finish the racetrack.
I wish to create a view where all the users personal bests on all maps are listed.
I tried creating the view like this:
CREATE VIEW map_pb AS
SELECT MID, UID, TID
FROM times
WHERE score IN (SELECT MIN(score) FROM times)
ORDER BY registered
This does not lead to the wished result.
Thank you for your help!
I hope that you have 'times' table created as the above diagram and 'score' column in the table that you use to measure the best record.
(MIN(score) is the best record).
You can simply create a view to have the personal best records using sub-queries like this.
CREATE VIEW map_pb AS
SELECT a.MID, a.UID, a.TID
FROM times a
INNER JOIN (
SELECT TID, UID, MIN(score) score
FROM times
GROUP BY UID
) b ON a.UID = b.UID AND a.score= b.score
-- if you have 'registered' column in the 'times' table to order the result
ORDER BY registered
I hope this may work.
You probably need to use a query that will first return the minimum score for each user on each map. Something like this:
SELECT UID,
MID,
MIN(score) AS best_time
FROM times
GROUP BY UID, MID
Note: I used MIN(score) as this is what is shown in your example query, but perhaps it should be MIN(time) instead?
Then just use the subquery JOINed to your other tables to get the output:
SELECT *
FROM (
SELECT UID,
MID,
MIN(score) AS best_time
FROM times
GROUP BY UID, MID
) a
INNER JOIN users u ON u.UID = a.UID
INNER JOIN maps m ON m.MID = a.MID
Of course, replace SELECT * with the columns you actually want.
Note: code untested but does give an idea as to a solution.
Start with a subquery to determine each user's minimum score on each map
SELECT UID, TID, MIN(time) time
FROM times
GROUP BY UID, TID
Then join that subquery into a main query.
SELECT times.UID, times.TID,
mintimes.time
FROM times
JOIN (
) mintimes ON times.TID = mintimes.TID
AND times.UID = mintimes.UID
AND times.time = mintimes.time
JOIN maps ON times.MID = maps.MID
JOIN users ON times.UID = users.UID
This query pattern uses a GROUP BY function to find the outlying (MIN in this case) value for each combination. It then uses that subquery to find the detail record for each outlying value.
I have the following table:
Company webdomain
------- ---------
IBM ibm.com
IBM ibm.co.uk
IBM ibm.in
CSC csc.com
Infosys infy.com
Intel intel.com
Intel intel.co.in
Question: how many companies have more than one webdomain?
How do I represent this as a SQL query?
I tried the following:
select count(distinct company, webdomain)
from table
where company = 'IBM';
This gave the number of web domains for IBM as 3, but however, when I want to create the same effect on finding out all companies with the following query:
select company, count(distinct company, webdomain)
from table;
I get a single column, which is an empty value on company and some unrelated count.
I know that this will solve the problem:
select company, count(distinct company, webdomain)
from table
where company in (select distinct company from table);
But this last query takes way too long. Is there a better way to put it.
EDIT: Company, webdomain combination may not be unique. Ex: Two records with IBM, ibm.com.
you can just append "Group by" in your query to get desired result as:-
SELECT
`company`, `webdomain`, COUNT(DISTINCT `company`, `webdomain`)
AS
`count_of_unique_combination` FROM `info`
GROUP BY
`company`;
the output is:-
COMPANY WEBDOMAIN COUNT OF UNIQUE COMBINATION
CSC csc.com 1
IBM ibm.com 3
Infosys infy.com 1
Intel intel.com 2
Use GROUP BY to get te desired result. Like:
select company, webdomain, count(*) from table group by company, webdomain;
Try with GROUP BY clause like
SELECT company,
count(*)
FROM TABLE
GROUP BY company,
webdomain;
As per
Question: How many companies have more than one webdomain?
You may use the following query
select
Company,
count(*) as num_subdomains
from
your_table
group by Company
having num_subdomains > 1
I have three tables as follows:
Contact, Custom_Field, Custom_Field_Value.
Each contact can have one Custom_Field_Value record for each Custom_Field. So there is a 1:many relationship between Contact and Custom_Field_Value but it isn't quite that simple.
Everything works fine - except for one edge case where I need to select Contacts that have a particular Custom_Field not set (i.e. no corresponding Custom_Field_Value record exists linking to the Contact and the Custom_Field). This is surprisingly difficult. I can't just use the normal "left join and look for NULL" approach because they may have a different custom field - but not the one I am looking for. I need to say "Where Custom_Field_ID=10" but I can't because the thing I'm looking for does not exist.
My line of thinking was heading in this direction, but I'm just tying myself in knots now:
Select ID, First_Name, Last_Name, CF_ID From
(
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact Inner Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Where Custom_Field_Value.CustomFieldID=23 Order By Contact.ID)
UNION
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Order by Contact.ID)
) as A
Group BY `ID`, CF_ID ASC
I don't want to create blank records for every possibility because there could be millions of records and every time someone adds a custom field, the database would have to insert millions of corresponding blank records.
It would be really great if we could do this:
Select ID From thingy
EXCLUDE
Select * From thingy Where x = true
This is a nasty one, but I know there'll be someone out there who will love it:)
Okay, I think I have a better understanding now. I was trying to pull it off without a subquery, but I'm not sure if I can.
Can you try
Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
WHERE NOT EXISTS(SELECT * FROM Custom_Field_Value cfv2 WHERE cfv2.ContactID = Contact.ID AND cfv2.CustomFieldID=23)
Order by Contact.ID
The NOT EXISTS subquery should only return rows where the contact has no value for that field.
This is the crazy SQL I ended up with - created dynamically by users. Just publishing it in case its any use to anyone. (Any tips on optimisation are very welcome!):
The problem is that not only do I have to select missing dynamic records, I also have to join together Left Join queries into one result.
SELECT * FROM (
(SELECT * FROM Contact
WHERE (...some dynamic stuff...)
)
UNION All
(SELECT Contact.* FROM Contact Inner Join Contact_Campaign_Link ON Contact.ID=Contact_Campaign_Link.Contact_ID
WHERE ((Campaign_ID=31))
)
UNION All
(SELECT * FROM Contact
WHERE (CustomerID=3)
AND (NOT EXISTS
(SELECT * FROM Custom_Field_Value cfv2
WHERE (cfv2.ContactID = Contact.ID)
AND (cfv2.CustomFieldID =27) )) ORDER BY Contact.ID)
) As tbl
GROUP BY tbl.ID HAVING COUNT(*)=3 Order by ID
Three very related SQL questions (I am actually using mySQL):
Assuming a people table with two columns name, country
1) How can I show the people who have fellow citizens? I can display the count of citizens by country:
select country, count(*) as fellow_citizens
from people
group by country
But I can't seem to show those records for which fellow_citizens is > 1. The following is invalid:
select name, country, count(*) as fellow_citizens
from people
group by country
where fellow_citizens > 1;
... and would not be what I want any way since I don't want to group people.
2) To solve the above, I had the idea to store fellow_citizens in a new column.
This sounds like a variation on questions such as MySQL: Count records from one table and then update another. The difference is that I want to update the same table.
However the answer given there doesn't work here:
update people as dest
set fellow_citizens =
(select count(*) from people as src where src.country = dest.country);
I get this error message:
You can't specify target table 'dest' for update in FROM clause
It seems like I need to through another temporary table to do that. Can it be done without a temporary table?
3) As a variant of the above, how can I update a column with a people counter by country? I found I can update a global counter with something like:
set #i:=0; update people set counter = #i:=#i+1 order by country;
But here I would like to reset my #i counter when the value of country changes.
Is there a way to do that in mySQL without going to full-blown procedural code?
Your select query should look something like:
SELECT name, country, count(*) as fellow_citizens
FROM people
GROUP BY country
HAVING fellow_citizens > 1;
Recommended solution
You don't want to group, you just want to repeat the count for every person.
This data is not normalized and code like this is not a great way to do things.
However the following select will give you all the people and their counts:
SELECT p.*
, s.fellow_citizens
FROM people p
INNER JOIN (
SELECT country, count(*) as fellow_citizens
FROM people
GROUP BY country
HAVING count(*) > 1) s ON (s.country = p.country)
If you don't want the actual count, just people from countries with more than 1 citizen, another way to write this query is (this may be faster than previous method, you have to test with your data):
SELECT p.*
FROM people p
WHERE EXISTS
( SELECT *
FROM people p2
WHERE p2.country = p.country
AND p2.PK <> p.PK -- the Primary Key of the table
)
Only do this if you are facing slowness
If you want to include the counts into the table using a update statement I suggest you use a separate count table, because at least that's somewhat normalized.
INSERT INTO people_counts (country, pcount)
SELECT p.country, count(*) as peoplecount
FROM people p
GROUP BY p.country
ON DUPLICATE KEY pcount = VALUES(pcount)
Then you can join the counts table with the people data to speed up the select.
SELECT p.*, c.pcount
FROM people p
INNER JOIN people_counts c ON (p.country = c.country)
1 ->
select country, count(*) as fellow_citizens
from people
group by country
having fellow_citizens > 1
Sorry, but could not really understand points 2 and 3.
I would do this.
create view citizencount as
select country, count(*) citizens
from people
group by country
Then your Query becomes (Something like)
select p.personid, p.country, cc.citizens -1 fellow_citizens
from people p
join citizencount cc on
cc.country = p.country
You might then want to add
where fellow_citizens > 0
Have you tried this for both of your problem
select name, fellow_citizens
from people left join
(select country, count(*) as fellow_citizens
from people group by country
having fellow_citizens > 1) as citizens
on people.country = citizens.country
I am not very good at writing sql query; but I think this can solve your problem