So basically, in my PHPMYADMIN I'm toying around with SQL injections so that I can eventually become a pen tester
SELECT *
FROM `ip` as ipstr
WHERE 'id' = $USERINPUT_HERE
ORDER BY
ipstr.id ASC
LIMIT 0 , 30
I'm having difficulty because it says that 'ipstr' is no longer defined when I try to inject it into my phpmyadmin.
I know that if it were a subquery, I would be able to do this. But its not a subquery, so how can I make something like the following work?
SELECT *
FROM `ip` as ipstr
WHERE 'id' = $USERINPUT_HERE
UNION ALL SELECT 1,2,3,4,5
ORDER BY
ipstr.id ASC
LIMIT 0 , 30
Somebody I know is saying it is possible to do this kind of injection, but I cannot figure out how to do it without rewriting the whole query and using subqueries. Thanks.
Let's see. If the string contained ''; delete ip; select * from (select 1 as id) ipstr, then the code might do something you don't expect. (To be honest, the entire statement might get rejected because it is multiple statements, but this is an example.)
The solution to SQL injection is to use parameterized queries. This is not a hard concept. And it is a good habit. You should get into that habit.
Related
I have tons of queries and wanna count their occurrence.
Problem: the same query can have different parameters.
I thought about using EXPLAIN and then hash the array.
But i guess that wont work well.
Is there any way to get a hash of a query without including the params and "style" (format?)?
F.e. can the mysql (mariadb) server return a prepared statement from a query?
(EDIT: i do not have the prepared statements from code. I got SQL strings only.)
Simple example:
SELECT * FROM foo where bar = 'baz
SELECT * FROM `foo` WHERE `bar` = 'baz';
SELECT * FROM `foo` WHERE `bar` = 3
SELECT * FROM `foo` WHERE `bar` = 3;
...
This is the same query with different "style" and different parameters.
What i would like to count up is the occurrence of SELECT * FROM `foo` WHERE `bar` = {.*};
Note: the queries will contain multiple joins, subqueries, ect.
In this case I got those SQL queries from a general_log table.
No code, just SQL strings.
It's not a question of "how can I do this better".
It's a "how can I get a better result from what I got".
You can get the count of queries by "digest" — a kind of anonymized version of the query with all constant values replaced with ? — from the performance_schema.
SELECT
SCHEMA_NAME,
digest,
digest_text,
round(sum_timer_wait/ 1000000000000, 6),
count_star
FROM performance_schema.events_statements_summary_by_digest
ORDER BY sum_timer_wait DESC LIMIT 10;
See https://www.percona.com/blog/2015/10/13/mysql-query-digest-with-performance-schema/ for a blog on this solution.
I've tried looking it up, and while I think this should be possible I can't seem to find the answer I need anywhere.
I need to lookup a date from one table, then store it for use in a following query.
Below is statements that should work, with my setting the variable (which I know won't work, but I'm unsure the best way to do/show it otherwise - bar maybe querying it twice inside the if statement.)
I'm then wanting to in the latter statement, use either the date given in the second query, or if the date from the first query (that I'm thinking to set as a variable) is newer, use that instead.
startDateVariable = (SELECT `userID`, `startDate`
FROM `empDetails`
WHERE `userID` = 1);
SELECT `userID`, SUM(`weeksGROSS`) AS yearGROSS
FROM `PAYSLIP`
WHERE `date` <= "2021-11-15"
AND `date` >= IF( "2020-11-15" > startDateVariable , "2020-11-15" , startDateVariable )
AND `userID` IN ( 1 )
GROUP BY `userID`
Naturally all dates given in the query ("2021-11-15" etc) would be inserted dynamically in the prepared statement.
Now while I've set the userID IN to just query 1, it'd be ideal if I can lookup multiple users this way at once, though I can accept that I may need to make an individual query per user doing it this way.
Much appreciated!
So turns I was going about this the wrong way, looks like the best way to do this or something similar is by using SQL JOIN
This allows you to query the tables as if they are one.
I also realised rather then using an IF, i could simply make sure i was looking up newer or equal to both the date given and the start date.
Below is working as required. And allows lookup of multiple users at once as wanted.
SELECT PAYSLIP.userID, employeeDetails.startDate, SUM(PAYSLIP.weeksGROSS) AS yearGROSS
FROM PAYSLIP
INNER JOIN employeeDetails ON employeeDetails.userID=PAYSLIP.userID
WHERE PAYSLIP.date <= "2021-11-15"
AND PAYSLIP.date >= "2020-11-15"
AND PAYSLIP.date >= employeeDetails.startDate
AND PAYSLIP.userID IN ( 1,2,8 )
GROUP BY PAYSLIP.userID
See here for more usage examples: https://www.w3schools.com/sql/sql_join.asp
However along the lines of my particular question, it's possible to store variables. I.E.
SET #myvar= 'Example showing how to declare variable';
Then use it in the SQL statement by using
#myvar where you want the variable to go.
Is there a limitation with the CONCAT function so that it cannot handle an IF statement? I have this query, that works if it is not a part of a CONCAT but as soon as I put it inside a CONCAT function it gives this error: #1583 - Incorrect parameters in the call to native function 'CONCAT'
SELECT CONCAT((IF(DAYOFYEAR(`deathdatetr`) and DAYOFYEAR(`birthdatetr`),TO_DAYS(`deathdatetr`) - TO_DAYS(`birthdatetr`),(YEAR(`deathdatetr`) - YEAR(`birthdatetr`)) * 365))/365.25 as totaldays, " years old") from tng_people order by totaldays limit 1;
This query should return the oldest person in the database (age in years). The table I am querying contains among other things, birth- and deathdates in the format "1860-07-30".
Can someone help me figure this out?
Your parentheses are messed up. You have a column alias in the middle of the expression. It is not surprising that MySQL is confused, because you seem to be as well.
It is fine to use if() where any expression is expected. I much prefer CASE (it is standard), but because you started with IF():
SELECT CONCAT(IF(DAYOFYEAR(`deathdatetr`) = DAYOFYEAR(`birthdatetr`),
TO_DAYS(`deathdatetr`) - TO_DAYS(`birthdatetr`),
(YEAR(`deathdatetr`) - YEAR(`birthdatetr`)) * 365)
) /365.25, ' years old') as total_years
from tng_people
order by totaldays
limit 1;
I have no idea what this logic is supposed to be doing. It doesn't seem useful, but that is another matter.
If you want the days between to dates:
select (to_days(deathdatetr) - to_days(birthdatetr)) as total_days
I figured it out, thanks to help from #Gordon. Apparently CONCAT() cannot handle what I THINK is called Aliasing, so once I removed that from the CONCAT() (the "...as total_days"), my query worked fine.
SELECT CONCAT ("A", FLOOR((to_days(`deathdatetr`) - to_days(`birthdatetr`))/365.25) ) from tng_people order by (to_days(`deathdatetr`) - to_days(`birthdatetr`)) DESC limit 1
Thanks for the help!
I want to know can i run a query in iif function used in ms access database. My case
Select field1,(iif(3<4,'Select * from tbl1','select * from tbl2')) from tblmain
I am facing syntax error when i try to executed query like that whats the problem
What you're trying to achieve isn't clear from your sample query.
You can use IIF functions in Access queries, for example:
SELECT IIF([SomeField]<15, "Smaller than 15", "Greater than!") As Whatever
FROM myTable
You can use subselects in Access as well, for example (example shamelessly stolen from http://allenbrowne.com/subquery-01.html):
SELECT MeterReading.ID, MeterReading.ReadDate, MeterReading.MeterValue,
(SELECT TOP 1 Dupe.MeterValue
FROM MeterReading AS Dupe
WHERE Dupe.AddressID = MeterReading.AddressID
AND Dupe.ReadDate < MeterReading.ReadDate
ORDER BY Dupe.ReadDate DESC, Dupe.ID) AS PriorValue
FROM MeterReading;
Note that the specified subselect query must be guaranteed to return a single record - either by specifying TOP 1 or using an aggregate function - and must link back to the parent query in the WHERE clause.
You can't use an IIF statement the way you're trying to in your question, however, even if your subselect was valid, which it is not.
Two options to suggest, although it is less than clear to me what you're trying to achieve here. First, you might want to consider doing it in VBA instead. Something like:
const query1 As String = "Select * from tbl1"
const query2 As String = "select * from tbl2"
Dim recset as DAO.Recordset
set recset = CurrentDB.OpenRecordset(iif(3<4, query1, query2))
Alternatively, if both tbl1 and tbl2 had the same fields you could do something like this:
SELECT * FROM tbl1 WHERE 3<4
UNION ALL
SELECT * FROM tbl2 WHERE NOT (3<4)
If you replace 3<4 by whatever actual condition you're checking for, you'll only get back records from one or the other or query, never both. However, my suspicion is that if you need to do this, your database may have design issues - I can think of many questionable scenarios where this would be needed, and few valid ones, although I'm sure they exist.
I have a mysql query, something like this:
SELECT users*100 as totalusers, totalusers*90 AS totalsalerys FROM table
As you can see I want to reuse the totalusers when calculating totalsalerys so I son't have to write the same code again. That dosen't seem to work in mysql, is there another easy way to do this?
My query is just an example, change the *100 and *90 to some very long formula and you might see what i mean..
SELECT (#r := users * 100) as totalusers,
#r * 90 AS totalsalerys
FROM table
You can also use a subquery as #Tom Ritter advices, but it's not friendly to ORDER BY ... LIMIT ... clause.
In MySQL, all results of the inner subquery will be fetched before applying any filters in the outer subquery.
I believe you would have to copy/paste the formula or use a subquery. The below would work in T-SQL, but I imagine it'd work in MySQL as well since it's pretty simple.
SELECT
x.totalusers, x.totalusers*90 AS totalsalerys
FROM (
SELECT users*100 as totalusers FROM table
) x