SQL find rows in the same table based on certain columns - mysql

I have two tables which are for two different programs. Each program has a specific program_instance (the program_instance) is the year of the program.
One table is called 'enrollees' and the other is 'nominations' - for two programs that aren't technically related.
I've been trying to get the count of past participants from both tables. For reference:
program_instance_id:
5 = GC 2014
3 = GC 2013
1 = GC 2012
4 = GE 2013
2 = GE 2012
So I ran this query on my enrollees table and it produced a result in 913ms:
SELECT count(*) AS prev_enrollees
FROM outreach.enrollees e1
WHERE e1.program_instance_id = 5 AND EXISTS
(SELECT * FROM outreach.enrollees e2
WHERE e1.first_name = e2.first_name
AND e1.last_name = e2.last_name
AND e1.address1 = e2.address1
AND e1.state = e2.state
AND e1.zip = e2.zip
AND e2.program_instance_id < 5);
This query, to my understanding, would give me the number of rows in the 'enrollees' table where an enrollee from the current year (program_instance_id = 5) had previous enrolled in another year. The result it produces is pretty accurate, to my understanding.
So... I ran this EXACT query (changing the table name) on my 'nominations' table. The nominations table has almost the exact structure of the 'enrollees' table (some columns are different, but the person's information fields are identical). This query ran for over a half hour before I cancelled it. It's not popping out an almost-instant result like it was on the enrollee table and I don't know why it would take longer.
I could imagine if there were a lot more rows in the table but the enrollee table has about 50k MORE rows than the nominations table.
I've also tried:
SELECT count(*) AS prev_enrollees
FROM outreach_grow_education.nominations e1
JOIN outreach_grow_education.nominations e2 ON e1.first_name = e2.first_name
AND e1.last_name = e2.last_name
AND e1.address1 = e2.address1
AND e1.state = e2.state
AND e1.zip = e2.zip
AND 4 = e2.program_instance_id
WHERE e1.id IS NOT NULL AND e1.program_instance_id = 2;
Alas, to the same result. Instant result on enrollees, never-ending on nominations.
Is there any other alternative for what I'm trying to achieve that wouldn't cause the never-ending cycle?

I suggest checking the indexes of the two tables, specifically for the columns you use in the JOIN clauses: first_name, last_name, address1, state, zip, and program_instance_id. Chances are one or more of these columns is indexed in the "enrollees" table and not in "nominations."

Related

Joining and selecting multiple tables and creating new column names

I have very limited experience with MySQL past standard queries, but when it comes to joins and relations between multiple tables I have a bit of an issue.
I've been tasked with creating a job that will pull a few values from a mysql database every 15 minutes but the info it needs to display is pulled from multiple tables.
I have worked with it for a while to figure out the relationships between everything for the phone system and I have discovered how I need to pull everything out but I'm trying to find the right way to create the job to do the joins.
I'm thinking of creating a new table for the info I need, with columns named as:
Extension | Total Talk Time | Total Calls | Outbound Calls | Inbound Calls | Missed Calls
I know that I need to start with the extension ID from my 'user' table and match it with 'extensionID' in my 'callSession'. There may be multiple instances of each extensionID but each instance creates a new 'UniqueCallID'.
The 'UniqueCallID' field then matches to 'UniqueCallID' in my 'CallSum' table. At that point, I just need to be able to say "For each 'uniqueCallID' that is associated with the same 'extensionID', get the sum of all instances in each column or a count of those instances".
Here is an example of what I need it to do:
callSession Table
UniqueCallID | extensionID |
----------------------------
A 123
B 123
C 123
callSum table
UniqueCallID | Duration | Answered |
------------------------------------
A 10 1
B 5 1
C 15 0
newReport table
Extension | Total Talk Time | Total Calls | Missed Calls
--------------------------------------------------------
123 30 3 1
Hopefully that conveys my idea properly.
If I create a table to hold these values, I need to know how I would select, join and insert those things based on that diagram but I'm unable to construct the right query/statement.
You simply JOIN the two tables, and do a group by on the extensionID. Also, add formulas to summarize and gather the info.
SELECT
`extensionID` AS `Extension`,
SUM(`Duration`) AS `Total Talk Time`,
COUNT(DISTINCT `UniqueCallID`) as `Total Calls`,
SUM(IF(`Answered` = 1,0,1)) AS `Missed Calls`
FROM `callSession` a
JOIN `callSum` b
ON a.`UniqueCallID` = b.`UniqueCallID`
GROUP BY a.`extensionID`
ORDER BY a.`extensionID`
You can use a join and group by
select
a.extensionID
, sum(b.Duration) as Total_Talk_Time
, count(b.Answered) as Total_Calls
, count(b.Answered) -sum(b.Answered) as Missed_calls
from callSession as a
inner join callSum as b on a.UniqueCallID = b.UniqueCallID
group by a.extensionID
This should do the trick. What you are being asked to do is to aggregate the number of and duration of calls. Unless explicitly requested, you do not need to create a new table to do this. The right combination of JOINs and AGGREGATEs will get the information you need. This should be pretty straightforward... the only semi-interesting part is calculating the number of missed calls, which is accomplished here using a "CASE" statement as a conditional check on whether each call was answered or not.
Pardon my syntax... My experience is with SQL Server.
SELECT CS.Extension, SUM(CA.Duration) [Total Talk Time], COUNT(CS.UniqueCallID) [Total Calls], SUM(CASE CS.Answered WHEN '0' THEN SELECT 1 ELSE SELECT 0 END CASE) [Missed Calls]
FROM callSession CS
INNER JOIN callSum CA ON CA.UniqueCallID = CS.UniqueCallID
GROUP BY CS.Extension

mysql query if there is no record or record.xx != xx trouble with query

I've 3 MYSQL tables.
"villa" table has records for properties.
"villa_type" table has records for property types.
"villa_price" table for daily prices with dates, price, property id and availability columns.
I receive all data with SQL, left join it with villa_type table to receive some additional info about property which works ok, and left join the table with the 3rd table to ask if the property is booked on that date or available.
Query is like this.
SELECT villa.*, villa_type.tip as villatypename
FROM villa
LEFT JOIN villa_type on villa_type.id = villa.type
LEFT JOIN villa_price on villa_price.villaid = villa.id
WHERE villa.lang = 1
AND villa.area = 1980
AND villa.status = 1
AND villa.status2 = 1
-- Problem starts here..............
AND (villa_price.vdate = '2015-01-13' OR villa_price.vdate is null)
AND (
((villa_price.condition != 2) AND (villa_price.condition != 3))
OR (villa_price.condition is null)
)
The problem is: if the villa has a record for 2015-01-13 and its condition is 2 or 3, i correctly don't get that villa listed (which is what i'm trying to do), but if that villa has a record for that same date and the condition is 1, it still doesn't get listed (while it should).
I simply want to check villa_price table to see that villa has a condition of 2 or 3 for the given date and eliminate that villa from result.
Any help or guide will be appreciated. Thanks alot

Mysql join queries not returning all rows as it should

I have an event software. The first table stores individuals who signed up for an event: EventIndividuals. I have a second table that stores the t-shirt they selected as a gift when they attend the event: EventIndividualShirtXref.
When I run the following query to see how many individuals are attending the 1st event it returns 31 rows correctly:
SELECT Id
FROM EventIndividuals
WHERE EventId = 1
Then when I run my second query to pair them up with a shirt it only returns 22 rows:
SELECT *
FROM EventIndividualShirtXref
WHERE EventIndividualId IN(SELECT Id FROM EventIndividuals WHERE EventId = 1)
I also tried running the next query using a join and it still only returns 22 rows:
SELECT esx.*
FROM EventIndividualShirtXref esx
INNER JOIN EventIndividuals ei
ON esx.EventIndividualId = ei.Id
WHERE ei.EventId = 1
I checked the indexing and the the columns are indexed correctly.
Is this enough info provided to figure out why the 31 rows are cut to 22?
This has never happened to me before and it makes no sense.

mysql select statement. why does it return 6 of the same record

When I make this sql statement I get 6 of the same record returned. So if I expect to get 2 records returned, I get six of each record back so that is 12 in total.
SELECT
ce2.*
FROM customerentry ce, customerentrytrace cet, customerentry ce2
WHERE ce.accountid = 1
AND ce.companyid = 1
AND ce.accountid=cet.accountid
AND ce.accountid=ce2.accountid
AND ce.companyid=cet.companyid
AND ce.companyid=ce2.companyid
AND cet.documentno = '2012Faktura1'
AND cet.documenttype = 1
AND ce2.documentno = cet.offsetdocumentno
AND ce2.documenttype = cet.offsetdocumenttype
ORDER BY created;
I know that I can solve it by adding distinct, but I would like to know why I get 6 of the same record returned. Anyone who can help me?
Since we have no idea about your table structure probably there are some columns that are related 1 to n items and you haven't handled them in the WHERE section of your query.
As an extra measure you can focus on your data needs and add a GROUP BY section before your ORDER section.
You are using an INNER JOIN, so for example there are two entries in table cet matching your where clause for combining table ce and cet, giving you 2 entries/entry of table ce.
Thinking this further you can see that if there are 3 entries in table ce2 matching the where clause for combining table cet and ce2 you get 3 entries/entry of table cet.
Which makes 6 entries per entry of table ce in total, giving you 12 entries in total even if you have only 2 entries in table ce.
So think again about what join could be the right for your desired solution.
Here a link for some more explanation: Short explanation of joins
Problem might be because you have not properly joined tables. Please read about JOIN
SELECT ce2.*
FROM customerentry ce INNER JOIN customerentrytrace cet ON ce.accountid=cet.accountid AND ce.companyid=cet.companyid,
INNER JOIN customerentry ce2 ON ce.accountid=ce2.accountid AND ce.companyid=ce2.companyid AND ce2.documentno = cet.offsetdocumentno AND ce2.documenttype = cet.offsetdocumenttype
WHERE ce.accountid = 1
AND ce.companyid = 1
AND cet.documentno = '2012Faktura1'
AND cet.documenttype = 1
ORDER BY created;

N or more continuous year range

I have to create a report using MySql DB where more than 4 tables are involved. I have one table (S1) with S1_ID and S1_Year_Range (strings like 2001-2002) and another table (S2) with S2_ID(PK), S2_Customer_ID, S1_ID (FK) and other fields for other conditions that can appear in Where clause of my query. There can be more than one row in S2 with the same S2_Customer_ID but different S1_ID. My query is to create a report using VB.net and ask users to enter two values; one number for how many continuous years or bigger (like >= 5 years), and a year range value (like 2011-2012) which is the highest value in the list for all customers.
My report lists customer names (by joining the above query with another table), customer rank and all year range values (highest at the bottom) for that customer in one column for each customer. Any help for this query would be appreciated.
Data and results could be like the following:
S1:
(S1_ID....S1_Year_Range)
(1......2000-2001)
(2......2001-2002)
(3......2002-2003)
(4......2003-2004)
(5......2004-2005)
etc
S2:
(S2_ID.....S2_Customer_ID.....S1_ID)
(1....1....1)
(2....1....2)
(3....1....3)
(4....2....2)
(5....2....3)
(6....2....5)
(7....3....2)
(8....3....3)
(9....3....4)
(10...3....5)
(11...4....3)
(12...4....4)
(13...4....5)
etc
when number 2 and year range (2003-2004) is entered by the user, the result should be the following:
customer 3 with 3 year range values (2003-2004, 2002-2003, and 2001-2002) and customer 4 with 2 year range values (2003-2004 and 2002-2003):
cname3
2001-2002
2002-2003
2003-2004
cname4
2002-2003
2003-2004
I hope you can see the columns of the report correctly.
I finally created a complex query to solve my problem. In the following query, I encoded the user year range value as '2010-2011' and number of continuous years as 14. Also a tiny difference with the question is the table names; table CSP here is the same as table S2 in my question but field names are the same as those in my question.
SELECT CSYWFY.S2_Customer_ID, COUNT(CSYWFY.S2_Customer_ID)
FROM (SELECT S1F.S1_Year_Range, S2.S2_Customer_ID , COUNT(S1F.S1_Year_Range) FROM CSP as S2 INNER JOIN S1 as S1F ON S2.S1_ID = S1F.S1_ID WHERE '2010-2011' IN (SELECT S1N.S1_Year_Range FROM CSP as S2N INNER JOIN S1 as S1N ON S2N.S1_ID = S1N.S1_ID WHERE S2N.S2_Customer_ID = S2.S2_Customer_ID ) GROUP BY S2.S2_Customer_ID ASC , S1F.S1_Year_Range DESC ) CSYWFY
GROUP BY CSYWFY.S2_Customer_ID
HAVING COUNT(CSYWFY.S2_Customer_ID) > 14
HTH