SQL Query tests not passing through - mysql

I was presented with this question during a technical test in HackerRank, I made several attempts to answer it and even asked a friend who's much more experienced than me
This is the code we ended up submitting:
SELECT name, count(*)
FROM employee
GROUP BY name, phone, age
HAVING COUNT(*) >1;
Using dummy data, I was getting the accurate result on MySQL workbench.
Is my query wrong? is the request poorly written? How can this be solved more efficiently (if possible at all)?

Your query is nearly correct, given the explanation of the requirments. But I have to say, what a terrible example of a question for this type of problem - please do not design schemas like this for your employer!
I say nearly correct since the actual requirement is just the names of the employees, so techincally you do not need to return the count(*) to satisfy the requirments.

Related

What does it mean to include a string in an SQL SELECT query

I apologize if the question asked is simple and far too stretched out
I've been studying the fundamentals of SQL Injection attacks and at a point, I've read that a potential method of verifying the data type of a particular field in a UNION SQL Injection attack is by making certain changes to the request that we make to the target server.
The software being used is BurpSuite, and the target is a practice lab on the website https://portswigger.net. It is told that the category field is vulnerable, and that the query for the category returns two fields, so the following "code" is appended to the category part of the HTTPS GET message that we send to the server in an attempt to know the data type of the first field
...?category=Gift'+UNION+SELECT+'abc',NULL+FROM+table_that_contains_target_information--
According to the manuals for the lab, what we're doing with the 'abc',NULL part is that we're verifying that the first field in the "table_that_contains_target_information", is of the type string/varchar. This seems to work and aids one in determining the data type of that particular field, as I checked in the lab, since if the first field's datatype is not a string/varchar, I would get an internal server error.
However, later on, when performing a query on a general database to check what the 'abc',NULL part does in a general SELECT query, the results that come are somewhat different.
The general database question is one that is available to use for learning SQL at https://www.w3schools.com/mysql. It has a table named Customers with several fields. I know for a fact that the first field is an integer (via verification with information_schema.columns), and the rest are varchars. For context, in the Customers table, CustomerID is an integer field, and CustomerName is a varchar field. I ran the following query on the server
|-------This part is the original query-------||This is our inserted code to find out information about the database|
SELECT CustomerID, CustomerName FROM Customers UNION SELECT 'abc',NULL FROM Customers
Disclaimer: My intentions were not to cause any harm to the database, only to learn some SQL
According to what I've learnt from the Lab manuals, I should be getting an error of sorts right?, since I'm checking the datatype of a field in a method that and unethical hacker could potentially take. However, all I get are the results of the original query and an extra record with values 'abc' and the second field is NULL.
I've tried to read up on documentation regarding the SELECT query in SQL, but as far as I was able to find, most of them tell about the general SELECT * FROM table_name or SELECT column_name, other_column_name FROM table_name. I wasn't able to find anything about the SELECT 'abc' FROM table_name.
Could anyone please explain what is going on here? Does the SELECT 'abc' FROM table_name just give me an extra record with 'abc'? If so, then why is this same query used to verify the datatypes in the lab at https://portswigger.net, and it seems to work its purpose there.
Thank you for answering in advance!

Is this SQL query correct

I'm preparing for an exam in databases and I stumbled upon this question:
We have a database of a human resources company, it contains the tables:
Applicant(a-id,a-city,a-name)
Qualified(a-id,job-id)
There are more tables in the database but they won't be relevant for the question I am asking.
The question was:
We want to write a query that displays for each pair (job-id,a-city) the names of the people living in that city who are qualified for the job.
Does this query solve the question? Why?
Select qualified.job-id, applicant.a-city, applicant.a-name
from qualified, applicant
where quailified.a-id=applicant.a-id
group by qualified.job-id, applicant.a-city
I personally think this query is fine. I can't find any faults with it, but lacking any actual way to check it, and also lacking experience with SQL, I would like someone to help me confirm that this is indeed okay.
I suspect you need to SELECT every value you want to return or compare, so you need to also select applicant.a-id
Select qualified.job-id, applicant.a-id, applicant.a-city, applicant.a-name
from qualified, applicant
where quailified.a-id=applicant.a-id
group by qualified.job-id, applicant.a-city
I'm really not happy with the GROUP BY for these, the output will be initially grouped into the different job id's and then each of those job id's will be grouped by city,
I also feel the question is not perfectly worded, in terms of what actual output is required but assuming that the user can select the city and the job, to list the people then the GROUP BYs are in fact SELECTers:
Select qualified.job-id, applicant.a-id, applicant.a-city, applicant.a-name
from qualified, applicant
where quailified.a-id=applicant.a-id
AND qualified.job-id = ? AND applicant.a-city = ? ORDER BY applicant.a-name
(I am well aware this does not use the preferred JOIN syntax, but I don't think the OP needs it in this case re: comments above).

Completely blind SQL injection column enumeration?

I'm doing a school project about webapp security and vulnerabilities, and for that i've made my own very simple website with a login and a search bar.
Now, i've made the login silent on purpose, while the search bar shows output on SQL injections. So for demonstration purposes I would like to do a time-based completely blind SQL injection attack on the login... But i'm a bit stuck.
I have no idea how I can enumerate how many columns are in the table for the login query, in a time-based situation:
SELECT * FROM customer WHERE cMAIL='' AND cPWD='';
I cannot do ORDER BY n;#, since I get absolutely no error output when something goes wrong. The only way I can get any indication is through SLEEP() or BENCHMARK().
But I cannot put ORDER BY into a SELECT IF() statement. So how can I find out how many columns exist? (it makes unions impossible for me).
Thank you!
EDIT: It might be worth mentioning, the site is very unsecure on purpose (doesn't use mysqli, just mysql). Since it is just for demonstration
Okay, I found an answer to my own question:
Instead of using ORDER BY, I used SELECT and bruteforced my way to see how many columns existed:
SELECT * FROM customer WHERE cMAIL='' AND cPWD='';
Can be enumerated in the dark by doing:
SELECT * FROM customer WHERE cMAIL='' UNION SELECT null,null,null AND SLEEP(5);# AND cPWD=''
You just keep adding more nulls to the select until the database sleeps for 5 seconds. Then you know how many columns are in the given table.
Hope this can help someone else.

Filter a MySQL Result in Delphi

I'm having an issue with a certain requirement to one of my Homework Assignments. I am required to take a list of students and print out all of the students with credit hours of 12 or more. The Credit hours are stored in a separate table, and referenced through a third table
basically, a students table, a classes table with hours, and an enrolled table matching student id to Course id
I used a SUM aggregate grouped by First name from the tables and that all works great, but I don't quite understand how to filter out the people with less than 12 hours, since the SQL doesn't know how many hours each person is taking until it's done with the query.
my string looks like this
'SELECT Students.Fname, SUM(Classes.Crhrs) AS Credits
FROM Students, Classes, Enrolled
WHERE Students.ID = Enrolled.StudentID AND Classes.ID = Enrolled.CourseID
GROUP BY Students.Fname;'
It works fine and shows the grid in the Delphi Project, but I don't know where to go from here to filter the results, since each query run deletes the previous.
Since it's a homework exercise, I'm going to give a very short answer: look up the documentation for HAVING.
Beside getting the desired result directly from SQL as Martijn suggested, Delphi datasets have ways to filter data on the "client side" also. Check the Filter property and the OnFilter record.
Anyway, remember it is usually better to apply the best "filter" on the database side using the proper SQL, and then use client side "filters" only to allow for different views on an already obtained data set, without re-querying the same data, thus saving some database resources and bandwidth (as long as the data on the server didn't change meanwhile...)

MS-Access design pattern for last value for a grouping

It's common to have a table where for example the the fields are account, value, and time. What's the best design pattern for retrieving the last value for each account? Unfortunately the last keyword in a grouping gives you the last physical record in the database, not the last record by any sorting. Which means IMHO it should never be used. The two clumsy approaches I use are either a subquery approach or a secondary query to determine the last record, and then joining to the table to find the value. Isn't there a more elegant approach?
could you not do:
select account,last(value),max(time)
from table
group by account
I tested this (granted for a very small, almost trivial record set) and it produced proper results.
Edit:
that also doesn't work after some more testing. I did a fair bit of access programming in a past life and feel like there is a way to do what your asking in 1 query, but im drawing a blank at the moment. sorry.
After literally years of searching I finally found the answer at the link below #3. The sub-queries above will work, but are very slow -- debilitatingly slow for my purposes.
The more popular answer is a tri-level query: 1st level finds the max, 2nd level gets the field values based on the 1st query. The result is then joined in as a table to the main query. Fast but complicated and time-consuming to code/maintain.
This link works, still runs pretty fast and is a lot less work to code/maintain. Thanks to the authors of this site.
http://access.mvps.org/access/queries/qry0020.htm
The subquery option sounds best to me, something like the following psuedo-sql. It may be possible/necessary to optimize it via a join, that will depend on the capabilities of the SQL engine.
select *
from table
where account+time in (select account+max(time)
from table
group by account
order by time)
This is a good trick for returning the last record in a table:
SELECT TOP 1 * FROM TableName ORDER BY Time DESC
Check out this site for more info.
#Tom
It might be easier for me in general to do the "In" query that you've suggested. Generally I do something like
select T1.account, T1.value
from table T as T1
where T1 = (select max(T2.time) from table T as T2 where T1.account = T2.Account)
#shs
yes, that select last(value) SHOULD work, but it doesn't... My understanding although I can't produce an authorative source is that the last(value) gives the last physical record in the access file, which means it could be the first one timewise but the last one physically. So I don't think you should use last(value) for anything other than a really bad random row.
I'm trying to find the latest date in a group using the Access 2003 query builder, and ran into the same problem trying to use LAST for a date field. But it looks like using MAX finds the lates date.
Perhaps the following SQL is clumsy, but it seems to work correctly in Access.
SELECT
a.account,
a.time,
a.value
FROM
tablename AS a INNER JOIN [
SELECT
account,
Max(time) AS MaxOftime
FROM
tablename
GROUP BY
account
]. AS b
ON
(a.time = b.MaxOftime)
AND (a.account = b.account)
;