I do not know how to join tables based on a calculation. I have to take a substring to get the part of a string I need to match up to a column from another table. I cannot figure out how to join them and really don't know where to start.
I tried everything in my power but I literally took a beginner's class and now have to fend for myself.
Select *
From five9_data.calllog join warbird.user
ON warbird.attr_employee = substring(five9_data.calllog.agent, 4,position('#' in five9_data.calllog.agent)- 4)
Group By warbird.attr_employee
Order warbird.attr_employee
Limit 100
I tried the above in the Select command but figured out it will not work and that I need to use the calculations in the join statement, but have no idea on syntax/formula. A few examples made as simple as possible would be great. I also have issue with the Group By Order by with this.
Shown above.
Often, the join condition would look like:
from t1 join
t2
on t1.empid = concat('%', t2.agent, '%')
Or, you can just use the expression:
from t1 join
t2
on t1.empid = substring(t2.agent, 4, position('#' in t2.agent) - 4)
EDIT:
As for your example code, I would write it as:
Select b.attr_employee, . . . -- aggregation functions go here
From five9_data.calllog cl join
warbird.user u
on u.attr_employee = substring(cl.agent, 4, position('#' in cl.calllog.agent) - 4)
Group By u.attr_employee
Order u.attr_employee
Limit 100;
Here are changes to notice:
Table aliases make the query easier to write and to read.
When using GROUP BY, the only unaggregated columns in the SELECT should be the GROUP BY keys. The rest should be aggregated.
Your problem is that warbird.attr_employee is not defined, because you have missed the table name. However, u is so much easier to write and to read.
from t1 join
t2
on t1.empid = substring(t2.agent, 4, position('#' in t2.agent) - 4)
Related
I have a table with exchange rate like below
And I am using the maxofdate to pick all these values based on currency code. But the query is giving blank.
Select USDAMOUNT * dbo.EXCHANGERATEAMT
from dbo.Amount_monthly
Left Join dbo.EXCHANGERATE on dbo.Amount_monthly.Currencycode=dbo.EXCHANGERATE.fromcurrencycode
WHERE ValidToDateTime = (Select MAX(ValidToDateTime) from dbo.EXCHANGERATE)
AND dbo.EXCHANGERATE.EXCHANGERATETYPECODE = 'DAY'
Using this statement
CONVERT(DATE,ValidToDateTime) = CONVERT(DATE,GETDATE()-1)
instead of subquery is giving me expected result.
Can someone correct this.
thanks in advance.
If I understand correctly, you need two things. First, the condition for the max() needs to match the condition in the outer query. Second, if you really want a left join, then conditions on the second table need to go in the on clause.
The resulting query looks like:
Select . . .
from dbo.Amount_monthly am Left Join
dbo.EXCHANGERATE er
on am.Currencycode = er.fromcurrencycode and
er.ValidToDateTime = (Select max(er2.ValidToDateTime)
from dbo.EXCHANGERATE er2
where er2.EXCHANGERATETYPECODE = 'DAY'
) and
er.EXCHANGERATETYPECODE = 'DAY';
I would write this using window functions, but that is a separate issue.
Try removing WHERE clause for ValidToDateTime and include it in the JOIN as AND condition
SELECT USDAMOUNT * dbo.EXCHANGERATEAMT
FROM dbo.Amount_monthly
LEFT JOIN dbo.EXCHANGERATE
ON dbo.Amount_monthly.Currencycode = dbo.EXCHANGERATE.fromcurrencycode
AND ValidToDateTime = (SELECT MAX(ValidToDateTime) --remove WHERE clause
FROM dbo.EXCHANGERATE)
AND dbo.EXCHANGERATE.EXCHANGERATETYPECODE = 'DAY';
I cleaned up your query a bit: as the other folks mentioned you needed to close the parentheses around the MAX(Date) sub-query, and if you reference a LEFT JOINed table in the WHERE clause, it behaves like an INNER JOIN, so I changed to in INNER. You also had "dbo" sprinkled in as a field prefix, but that (the namespace) only prefixes a database, not a field. I added the IS NOT NULL check just to avoid SQL giving the "null values were eliminated" SQL warning. I used the aliases "am" for the first table and "er" for the 2nd, which makes it more readable:
SELECT am.USDAMOUNT * er.EXCHANGERATEAMT
FROM dbo.Amount_monthly am
JOIN dbo.EXCHANGERATE er
ON am.Currencycode = er.fromcurrencycode
WHERE er.ValidToDateTime = (SELECT MAX(ValidToDateTime) FROM dbo.EXCHANGERATE WHERE ValidToDateTime IS NOT NULL)
AND er.EXCHANGERATETYPECODE = 'DAY'
If you're paranoid like I am, you might also want to make sure the exchange rate is not zero to avoid a divide-by-zero error.
Really trying to figure out, why SQL query doesnt go through. I assume the structure is a bit wrong, but cant figure out where exactly. The references to tables are all correct.
SELECT tap_questionnaires.id,
tap_questionnaires.NAME,
tap_questionnaires.active,
tap_useranswers_ip.questionnaire_id,
Count(tap_useranswers_ip.ip)
FROM tap_questionnaires
LEFT JOIN tap_useranswers_ip
ON tap_questionnaires.id = tap_useranswers_ip.questionnaire_id
WHERE author_email = admin#admin.com
If you use count you need to use group by for the other columns in your select clause.
SELECT TAP_questionnaires.id, TAP_questionnaires.name, TAP_questionnaires.active, TAP_useranswers_ip.questionnaire_id, COUNT(TAP_useranswers_ip.ip) FROM TAP_questionnaires LEFT JOIN TAP_useranswers_ip on TAP_questionnaires.id=TAP_useranswers_ip.questionnaire_id WHERE author_email="admin#admin.com"
group by TAP_questionnaires.id, TAP_questionnaires.active
I think TAP_questionnaires.name it's not necessary because I suppose it depends on TAP_questionnaires.id. TAP_useranswers_ip.questionnaire_id is the same value as TAP_questionnaires.id
Hope that helps!
I think this version is clearer:
SELECT q.id, q.name, q.active, COUNT(a.ip)
FROM TAP_questionnaires q LEFT JOIN
TAP_useranswers_ip a
ON on q.id = a.questionnaire_id
WHERE author_email = 'admin#admin.com'
GROUP BY q.id, q.name, q.active;
Notes:
You need a GROUP BY.
You need single quotes around the string constant.
Table aliases make the query easier to write and to read.
There is no reason to include a.questionnaire_id. You already have q.id.
I have a query which is taking more time to execute . I am trying to optimize it. There are functions in the GROUP BY which may be adding to the query time . So i am trying to figure out how to optimize that part.
I am using Mysql 5.5.17 .
I cannot use force index as i am using Hibernate, so that's out of option .
I have some other options like :
1) use the alias in place of concat(...) in group by.
2) or replace concat() with the the columns inside it .
Ex: group by concat(1,2,3.) => group by 1,2,3
After trying both the above options i dont see any difference in "Query Cost"
The query looks like this(table names changed) :
select sum(this_.a + this_.b + this_.c + this_.d + this_.e +
this_.f + this_.g + this_.h + this_.i + this_.j) as sent,
sum(this_.a + this_.b + this_.c + this_.d + this_.e) as delivered,
d2_.name as y2_, d2_.id as y3_, concat(cast(b4_.id as char),
'.',c1_.name,'.',cs5_.name,'_',date_format(b4_.createddate,
'%Y-%b-%d %H:%i:%s')
) as allias_concat, b4_.id as y5_,
this_.year as y6_, this_.month as y7_, this_.day as y8_,
this_.weekday as y9_, this_.weekofmonth as y10_,
this_.bltid as y11_,
b4_.id as y12_, c1_.name as y13_,
cs5_.name as y14_, b4_.createddate as y15_,
cs5_.subject as y16_, d2_.name as y17_
from TABLE1 this_
inner join TABLE2 c1_ on this_.cgnid=c1_.id
inner join TABLE3 b4_ on this_.bltid=b4_.id
inner join TABLE4 csc6_ on b4_.schdlid=csc6_.id
inner join TABLE5 cs5_ on this_.constid=cs5_.id
left outer join TABLE6 f3_ on this_.fid=f3_.id
inner join TABLE7 d2_ on this_.dptid=d2_.id
where (f3_.name<>'TRASH'
or c1_.fid=0
)
and c1_.status<>'K'
and d2_.id in (1)
and ((b4_.createddate between '2015-02-01 10:30:00'
AND '2015-05-13 10:29:59'
and csc6_.isrealtime = 'N'
)
or (csc6_.isrealtime = 'Y'
and this_.bltdate between '2015-02-01 10:30:00'
AND '2015-05-13 10:29:59')
)
group by d2_.id,
concat(cast(b4_.id as char),'.',c1_.name,'.',cs5_.name,'_',
date_format(b4_.createddate,'%Y-%b-%d %H:%i:%s')
),
b4_.id,
this_.year, this_.month, this_.day,
this_.bltid
limit 20001
Please suggest ...
Thanks In Advance ...
Sorry, but this is going to be an "anti-answer"...
It smells like "over-normalization". For example, it feels like b4_ is a normalization of a datetime (createddate) and nothing else. Is this correct? If so, that is adding complexity and slowing down both the WHERE and the GROUP BY, plus obliterating some optimization possibilities.
The "functions" are not the problem. Since the items in the GROUP BY are coming from different tables, there is no way to optimize it. The GROUP BY must gather the information from the various tables, put them in a temp table, sort it, then scan through it. (Or something like that. The point is that there is no shortcut.)
"I cannot use ... as i am using Hibernate" -- Yet another case where a 3rd party software "gets in the way". If you can't change the query, we can't help you.
I have a query as follows
select
Sum(If(departments.vat, If(weeklytransactions.weekendingdate Between
'2011-01-04' And '2099-12-31', weeklytransactions.takings / 1.2,
If(weeklytransactions.weekendingdate Between '2008-11-30' And '2010-01-01',
weeklytransactions.takings / 1.15, weeklytransactions.takings / 1.175)),
weeklytransactions.takings)) As Total,
weeklytransactions.weekendingdate,......
and another that returns a vat rate as follows
select format(Max(Distinct vat_rates.Vat_Rate),3) From vat_rates Where
vat_rates.Vat_From <= '2011-01-03'
I want to replace the hard coded if statement with the lower query, replacing the date in the lower query with weeklytransactions.weekendingdate.
After Kevin's comments, here is the full query I'm trying to get to work;
Select Max(vat_rates.vat_rate) As r,
If(departments.vat, weeklytransactions.takings / r, weeklytransactions.takings) As Total,
weeklytransactions.weekendingdate,
Week(weeklytransactions.weekendingdate),
round(datediff(weekendingdate, (if(month(weekendingdate)>5,concat(year(weekendingdate),'-06-01'),concat(year(weekendingdate)-1,'-06-01'))))/7,0)+1 as fyweek,
cast((Case When Month(weeklytransactions.weekendingdate) >5 Then Concat(Year(weeklytransactions.weekendingdate), '-',Year(weeklytransactions.weekendingdate) + 1) Else Concat(Year(weeklytransactions.weekendingdate) - 1, '-',Year(weeklytransactions.weekendingdate)) End) as char) As fy,
business_units.business_unit
From departments Inner Join (business_units Inner Join weeklytransactions On business_units.buID = weeklytransactions.businessUnit) On departments.deptid = weeklytransactions.departmentId
Where (vat_rates.vat_from <= weeklytransactions.weekendingdate and business_units.Active = true and business_units.sales=1)
Group By weeklytransactions.weekendingdate, business_units.business_unit Order By fy desc, business_unit, fyweek
Regards
Pete
Assuming I read your question correctly, your problem is about having the result of another SELECT used to be returned by the result of your main query (plus depending on how acquainted you are with SQL, maybe you haven't had the occasion to learn about JOINs?).
You can have subqueries you extract data from within a SELECT, provided you define it within the FROMclause. The following query will work, for example:
SELECT A.a, B.b
FROM A
JOIN (SELECT aggregate(c) FROM C) AS B
Notice that there is no reference to table A within the subquery. Thing is, you cannot just add it like that to the query, as the subquery doesn't know it is a subquery. So the following won't work:
SELECT A.a, B.b
FROM A
JOIN (SELECT aggregate(c) FROM C WHERE C.someValue = A.someValue) AS B
Back to basics. What you want to do here visibly, is to aggregate some data associated to each of the records of another table. For that, you will need merge your SELECT queries and use GROUP BY:
SELECT A.a, aggregate(C.c)
FROM A, C
WHERE C.someValue = A.someValue
GROUP BY A.a
Back to your tables, the following should work:
SELECT w.weekendingdate, FORMAT(MAX(v.Vat_Rate, 3)
FROM weeklytransactions AS w, vat_rates AS v
WHERE v.Vat_From <= w.weekendingdate
GROUP BY w.weekendingdate
Feel free to add and remove fields and conditions as you see fit (I wouldn't be surprised that you'd also want to use a lower bound when filtering the records from vat_rates, since the way I have written it above, for a given weekendingdate, you get records from that week + the weeks before!).
So it looks like my first try did not address the actual problem. With the additional information provided in the comments, as well as the new complete query, let's see how this goes.
We are still missing error messages, but normally the query as written should result in MySQL having the following complaint:
ERROR 1109 (42S02): Unknown table 'vat_rates' in field list
Why? Because the vat_rates table does not appear in the FROM clause, whereas it should. Let's make that more obvious by simplifying the query, removing all references to the business_units table as well as the fields, calculations and order that do not add or remove anything to the problem, leaving us with the following:
SELECT MAX(vat_rates.vat_rate) AS r,
IF(d.vat, w.takings / r, w.takings) AS Total
FROM departments AS d
INNER JOIN weeklytransactions AS w ON w.departmentId = d.deptid
WHERE vat_rates.vat_from <= w.weekendingdate
GROUP BY w.weekendingdate
That cannot work, and will produce the error mentioned above. It looks like there is no FOREIGN ID between the weeklytransactions and vat_rates tables, so we have no choice but to do a CROSS JOIN for the moment, hoping that the condition in the WHERE clause and the aggregate function used to get r are enough to fit the business logic at hand here. The following query should return the expected data instead of an error message (I also remove r since that seems to be an intermediate value judging by the comments that were written):
SELECT IF(d.vat, w.takings / MAX(v.vat_rate), w.takings) AS Total
FROM vat_rates AS v, departments AS d
INNER JOIN weeklytransactions AS w ON w.departmentId = d.deptid
WHERE v.vat_from <= w.weekendingdate
GROUP BY w.weekendingdate
From there, assuming it works, you will only need to put back all the parts I removed to get your final query. I am a tad doubtful about the way the VAT rate is gotten here, but I have no idea what your requirements are in that regard so I leave it up to you to make sure that works as expected.
I know this has been asked plenty times before, but I cant find an answer that is close to mine.
I have the following query:
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, o.organisation_name
FROM db_cases c, db_custinfo ci, db_organisation o
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2'
AND organisation_name = (
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
)
AND s.sites_site_ID = c.sites_site_ID)
What I am trying to do is is get the cases, where the sites_site_ID which is defined in the cases, also appears in the db_sites sites table alongside its organisation_ID which I want to filter by as defined by "organisation_ID = '111'" but I am getting the response from MySQL as stated in the question.
I hope this makes sense, and I would appreciate any help on this one.
Thanks.
As the error states your subquery returns more then one row which it cannot do in this situation. If this is not expect results you really should investigate why this occurs. But if you know this will happen and want only the first result use LIMIT 1 to limit the results to one row.
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
LIMIT 1
Well the problem is, obviously, that your subquery returns more than one row which is invalid when using it as a scalar subquery such as with the = operator in the WHERE clause.
Instead you could do an inner join on the subquery which would filter your results to only rows that matched the ON clause. This will get you all rows that match, even if there is more than one returned in the subquery.
UPDATE:
You're likely getting more than one row from your subquery because you're doing a cross join on the db_sites and db_cases table. You're using the old-style join syntax and then not qualifying any predicate to join the tables on in the WHERE clause. Using this old style of joining tables is not recommended for this very reason. It would be better if you explicitly stated what kind of join it was and how the tables should be joined.
Good pages on joins:
http://dev.mysql.com/doc/refman/5.0/en/join.html (for the right syntax)
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html (for the differences between the types of joins)
I was battling this for an hour, and overcomplicated it completely. Sometimes a quick break and writing it out on an online forum can solve it for you ;)
Here is the query as it should be.
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, c.sites_site_ID
FROM db_cases c, db_custinfo ci, db_sites s
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2' AND (s.organisation_ID = '111' AND s.sites_site_ID = c.sites_site_ID)
Let me re-write what you have post:
SELECT
c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName,
c.cases_timestamp, c.sites_site_ID
FROM
db_cases c
JOIN
db_custinfo ci ON c.userInfo_ID = ci.userinfo_ID and c.cases_status = '2'
JOIN
db_sites s ON s.sites_site_ID = c.sites_site_ID and s.organization_ID = 111