I have a simple query in my code (shown below) written by my colleague. What does t mean here? Also what is the role of the ; inside the query? I am dead sure that t is not any table, nor any field anywhere in my database. And guess what this query works!!
string query = #"SELECT COUNT(*) FROM (SELECT AttemptNo FROM attempt_exercise
WHERE FK_UId = #uId AND FK_EId = #eId AND Mode = #mode)t;
";
The code follows like this (for any other info if required):
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#uId", uId);
cmd.Parameters.AddWithValue("#eId", eId);
cmd.Parameters.AddWithValue("#mode", mode);
attemptCount = Convert.ToInt32(cmd.ExecuteScalar());
_conn.Close();
return attemptCount;
Your colleague created a query (SELECT COUNT(*)) with a subquery that he named t. This t is just a temporary table name which refers to
SELECT AttemptNo FROM attempt_exercise
WHERE FK_UId = #uId AND FK_EId = #eId AND Mode = #mode
He could have feasibly named it temp to be a bit more explicit. The reason that this becomes like a table is because, in MySQL, a SELECT query returns rows of data which act like a table. So, this inner query gets the AttemptNo, and creates a temporary table t. The outer query then counts this data.
The ; inside the query is to make it a full statement when the string query is called by the program. If this weren't included, the String query wouldn't contain a valid MySQL statement. The final ; is to complete the assignment for the variable.
t is an alias for your subquery, and you need it.
So you could have written:
SELECT COUNT(*) FROM attempt_exercise
WHERE FK_UId = #uId AND FK_EId = #eId AND Mode = #mode;
and that would have been equivalent.
But were you to try to join your subquery to something else, you would have likely seen the need a bit sooner:
SELECT COUNT(*) FROM
(SELECT AttemptNo FROM attempt_exercise
WHERE FK_UId = #uId AND FK_EId = #eId AND Mode = #mode) t
JOIN AttemptStatisticsTableOfSomeSort a
ON t.AttemptNo = a.AttemptNo;
An alias to the subquery. If subquery appears as tablesource in FROM or JOIN clauses - it should have an alias.
It is just an alias for the nested query. The semi colon inside the query is a statement terminator - its part of the ANSI sql standard.
All temporary tables created in this manner (ie. in the FROM clause) MUST have an alias they can be referred to by. In this case, the alias is t. If the coder were more clear in their writing, they wouldn't have omitted the optional AS before it.
The point is, it's just a temporary name and not really important in this scenario, but it required to make it work.
That said, the following is probably more efficient:
SELECT COUNT(DISTINCT AttemptNo) FROM attempt_exercise WHERE FK_UId = #uId AND FK_EId = #eId AND Mode = #mode
The semi colon is a line delimiter for MySql commands. Have a look under the first bullet point on here for more info: http://dev.mysql.com/doc/refman/5.0/en/entering-queries.html
Related
I need to write a sequence of queries where I want to sometimes use a different table or database and don't want to keep writing them over and over again which can lead to a mistake.
SET #NAME = "Fred";
SELECT pid FROM old_table.people WHERE name = #NAME INTO #PID;
INSERT new_table.address SELECT *
FROM old_table.address o WHERE o.pid = #PID;
...
Is there a way todo a global SET or ALIAS so I don't have to repeat the database.table names again and again with the chance of a typo.
ie looking for something like this - this is not real sql
ALIAS old_table.people #OP;
ALIAS new_table.people #NP;
ALIAS old_table.address #OA;
ALIAS new_table.address #NA;
SET #NAME = "Fred";
SELECT pid FROM #OP WHERE name = #NAME INTO #PID;
INSERT #NA SELECT * FROM #OA o WHERE o.pid = #PID;
The closest thing to what you ask for is a VIEW. But I don't see how this would help avoid typos. You'd just be swapping one name for another name. You could make a typo on the view name just as easily.
You definitely cannot use a user-defined variable as a table identifier. When you use a variable in a query, it is as if you used a string value.
I want to optimize these SQL queries using if-else but how I should use it? .
if this query result contain 'ALL'
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856'
Then i want to query this
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1
GROUP BY subcategoryName
ORDER BY subcategoryName
otherwise take query1 result .
The problem is that if we do not refactor your project, then you always have to evaluate query1 and see whether it contains All or not. If it does not contain All, then you need to evaluate query2 as well. This can hardly be optimized, let's see a few approaches:
Quickening query1
Since All might be not be the very last evaluated element, adding it to the filter and limiting it is a good idea to quicken query1:
SELECT
COUNT(*)
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856' AND
bdsubcategory.subcategoryName = 'ALL'
LIMIT 0, 1
So, you could create a stored procedure which evaluates query1' (query1' is the quickened version of query1, as seen above) and if there is a result, then we need to execute query1. Otherwise we need to execute query2. This way you still execute two queries, but the first query is optimized.
Refactoring
Note that the second query does not change. You could create a table where you could cache its results, using a periodic job. Then, you could skip the second table to
SELECT ID, Name
FROM MyNewTable;
without the many joins. You would also cache the results of the first query into a table where the items having ALL would be stored and query that table.
One option would be to use a CASE.
Change this:
newsms_person.personID = '856'
To this:
'Y' = CASE WHEN UPPER('856') = 'ALL' THEN 'Y'
WHEN newsms_person.personID = '856' THEN 'Y'
ELSE 'N' END
Alternatively, a stored procedure could be used to first validate whether the personID seems valid, then returns the appropriate data.
I am getting an error:
1052 - Column 'orderId' in where clause is ambiguous
when trying to do CALL GetOrderById(2000)
BEGIN
SELECT
hsorders.*,
hslineitem.partNum, hslineitem.price
FROM
hsorders
JOIN hslineitem ON hslineitem.orderId = hsorders.orderId
WHERE
orderId = orderId;
END
I need to pass an Id and join data from two tables that have the same `orderId``.
What am I doing wrong?
You are getting the error because orderid is in both tables. Hence, the SQL engine does not know which orderid the where clause refers to.
Let me hypothesize that you have a parameter or variable called orderid.
That name conflicts with columns of the same name in the table. That is why I use prefixes. For instance, if orderid is being passed in as a parameter, I would name it in_orderid. If it were a local variable, I might use v_orderid.
Then the code would look like this:
BEGIN
SELECT o.*, li.partNum, li.price
FROM hsorders o JOIN
hslineitem li
ON li.orderId = o.orderId
WHERE o.orderId = v_orderId;
END;
Notice that I also added table aliases so the query is easier to write and to read.
You need to use alias:
BEGIN
SELECT
hsorders.*,
hslineitem.partNum, hslineitem.price
FROM hsorders
JOIN hslineitem ON hslineitem.orderId = hsorders.orderId
WHERE
hsorders.orderId = p_orderId; -- I suggest to rename parameter to avoid
-- name collision
END
ambiguous means use table name or alias name before FIELD
Like hsorders.orderId in where clause.
Use alias while joining tables. It will be helpful to distinguish the columns if they are in both the tables.
When to use alias
BEGIN
SELECT
HO.*,
HL.partNum, HL.price
FROM
hsorders HO
JOIN hslineitem HL
ON HO.orderId = HL.orderId
END
you have already used ON clause to give HO.orderId = HL.orderId
so you do not have to use where clause again
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.
I am trying to do an INNER JOIN on two tables that have similar values, but not quite the same. One table has a fully qualified host name for its primary key, and the other the hosts short name, as well as the subdomain. It it safe to assume that the short name and the subdomain together are unique.
So I've tried:
SELECT table1.nisinfo.* FROM table1.nisinfo INNER JOIN table2.hosts ON (table1.nisinfo.shortname + '.' + table1.nisinfo.subdomainname + '.domain.com') = table2.hosts.fqhn WHERE table2.hosts.package = 'somepkg';
This doesn't return the results I expect, it returns the first result hundreds of times. I'd like to return distinct rows. It takes a long time to run as well.
What am I doing wrong? I was thinking of running a subquery to get the hostnames, but I don't know what the right path from here is.
Thank you!
You can use group by in your query so you can achieve the desired results you want
please see this two links
Group by with 2 distinct columns in SQL Server
http://www.sqlteam.com/article/how-to-use-group-by-with-distinct-aggregates-and-derived-tables
Try putting your results into a temp table and then view the table to make sure that the columns are as expected.
SELECT table1.nisinfo.*, table1.nisinfo.shortname + '.' + table1.nisinfo.subdomainname + '.domain.com' AS ColID
INTO #temp
FROM table1.nisinfo;
Select *
from #temp INNER JOIN table2.hosts ON ##temp.ColID = table2.hosts.fqhn
WHERE table2.hosts.package = 'somepkg'
;
Put a Group By clause at the end of the second statement
So in this case, I used a subquery to get the initial results, and then used a join.
SELECT table1.nisinfo.* FROM table1.nisinfo JOIN (SELECT distinct(fqhn) FROM table2.hosts WHERE package = 'bash') AS FQ ON ((SUBSTRING_INDEX(FQ.fqhn, '.', 1)) = table1.nisinfo.shortname);