How to make this query faster? - sql

My Db look like this:
id | Column1 | Column2
Must known facts: id is not a primary unique id (but could be). id can go up to 2Millions+. Column values are filled with TINYINT
var query : String = "SELECT Column1 FROM Table1 WHERE Column1 <> 0";
dbcmd = dbcon.CreateCommand();
dbcmd.CommandText = query;
reader = dbcmd.ExecuteReader();
var result : int = 0;
while(reader.Read()) {
result++;
}
return result;
But for a basic search it makes up to 5 seconds, is there anyway to make it faster?
Edit: Like always, thanks for the contributors and the rapidity!

Yes, you are reading your results and processing them one by one. All you seem to be doing to need is the count, which you can get with:
"SELECT COUNT(*) FROM Table1 WHERE Column1 <> 0";

This doesn't look like javascript code, but you could try counting the records instead of executing the query and then looping through the entire resultset on the client and increment a variable:
var query : String = "SELECT Count(Column1) FROM Table1 WHERE Column1 <> 0";
This will be much faster than your code because the count operation will be done by the database server directly.

Yes, index the table on Column1, the row used in the where clause.

Related

Create a SQL select query dynamically at runtime

I have a requirement where I need to write a SQL select query with dynamic columns at runtime. There are few mandatory and optional fields in the DB. I want to generate the query at runtime based on the values present in the incoming request.
Ex: DB has colms A,B,C,D,E
scenario 1: request has only value for A, query should be generated as
select * from table where A='<somevalue>'
scenario 2 . Request has value for A and D , query should be generated as
select * from table where A='<somevalue>' and D='<somevalue>'
Currently it is being handled using java to create string for not null values and appending it to select statement to form the final query.
Ex:
if (A!=null)
String query_a='<somevalue>'
else
query_a=""
and then appending <query_a> <query_b> to form final query
Is there a better way to achieve this?
In your SQL script, you can better parametrize like below. I've assume that you are using parameters.
**It's basically sql idea.
SELECT *
FROM table
WHERE (
(#p1 IS NULL OR columnA = #p1)
OR (#p2 IS NULL OR columnB = #p2)
OR (#p3 IS NULL OR columnC = #p3)
OR (#p4 IS NULL OR columnD = #p4)
)
You may want to consider doing this construction of queries in Java, creating an appropriate Prepared Statement for each case.
List<String> clauses = new ArrayList<String>();
List<String> params = new ArrayList<String>();
clauses.add("1=1");
if (you_want_to_search_on_column_a) {
clauses.Add("column_a = ?");
params.Add(value_to_search_on_column_a);
}
if (you_want_to_search_on_column_b) {
clauses.Add("column_b = ?");
params.Add(value_to_search_on_column_b);
}
String queryString = "SELECT * FROM table WHERE " + String.join(" AND ", clauses);
PreparedStatement stmt = con.prepareStatement(queryString);
for (int i = 0; i < params.size; i++ ) {
stmt.setString(i+1, params.get(i));
}
ResultSet rs = stmt.executeQuery();
This way you'll present queries with exactly the filtering criteria you need, and so give MySQL's query planner the best possible shot at optimizing each one.
If you were working with Oracle or SQL server it would be worth your trouble to keep a cache of PreparedStatement objects, but that's not so with MySQL.

I need to get a distinct list based on a column in SQL

var sqlStatement = string.Format("select * from CardDecks where deckid = {0}", id);
var getcardid = db.CardDecks.SqlQuery(sqlStatement).ToList();
var getDistinct = getcardid.Distinct().ToList();
What I expect from this code is for the last list to only pull distinct values but it still pulls duplicates. I need for it to only pull back the list with unique values based on cardid. What am I missing?
I changed the SQL statement to this and it works:
List<CardDeck> distictList = getcardid.GroupBy(p => p.CardID).Select(g => g.First()).ToList();
You could write your query like this:
select distinct column1, column2, column3 from CardDecks where deckid = {0}
... where column1, column2, column3 are the columns that you want to show.

SQL: Where MYID = ANY?

In a SQL query, that contains
... WHERE MYID = #1 ....
I have to manage 2 cases
1) There is a filter on a column, #1 will be a number (1,2,X...)
2) There is no filter on that column, #1 will be ...? (ANY)
Is there something for this "any" (SQL Server 2005) ?
PS.
Obviously, I understand that I can remove the "where".
PPS.
I explain myself for better understanding: I have this query in the code, and would like to pass an integer as parameter when the filter is ON, and "something" when my filter is OFF.
if (filterOn)
GetFoos(fooID);
else
GetFoos("ANY");
GetFoos(param1): "select * from FOOS where FOOID = {0}", param1
Make a UNION ALL of the two statements:
SELECT *
FROM mytable
WHERE myid = #col
UNION ALL
SELECT *
FROM mytable
WHERE #col IS NULL
or just split them in an IF / ELSE block of a stored procedures.
Either way, the optimizer will be able to optimize the queries separately, completely ignoring one of them depending on the value of #col.
you could do something along this line:
where (myid = #id or #id is null)
so you will only filter when #id contains a value and not when it is null.
Just remove the where or and clause if there is no filter on that column.
If you don't want to filter on a particular column, just don't filter on that column. Remove the WHERE MYID = entirely
Having
"select * from FOO where FOOID = {0}", param
use param="FOOID" when there is no param to filter, this will give
select * from FOO where FOOID = FOOID // removing the filter

Updating a table within a select statement

Is there any way to update a table within the select_expr part of a mysql select query. Here is an example of what I am trying to achieve:
SELECT id, name, (UPDATE tbl2 SET currname = tbl.name WHERE tbl2.id = tbl.id) FROM tbl;
This gives me an error in mysql, but I dont see why this shouldn't be possible as long as I am not changing tbl.
Edit:
I will clarify why I cant use an ordinary construct for this.
Here is the more complex example of the problem which I am working on:
SELECT id, (SELECT #var = col1 FROM tbl2), #var := #var+1,
(UPDATE tbl2 SET col1 = #var) FROM tbl WHERE ...
So I am basically in a situation where I am incrementing a variable during the select statement and want to reflect this change as I am selecting the rows as I am using the value of this variable during the execution. The example given here can probably be implemented with other means, but the real example, which I wont post here due to there being too much unnecessary code, needs this functionality.
If your goal is to update tbl2 every time you query tbl1, then the best way to do that is to create a stored procedure to do it and wrap it in a transaction, possibly changing isolation levels if atomicity is needed.
You can't nest updates in selects.
What results do you want? The results of the select, or of the update.
If you want to update based on the results of a query you can do it like this:
update table1 set value1 = x.value1 from (select value1, id from table2 where value1 = something) as x where id = x.id
START TRANSACTION;
-- Let's get the current value
SELECT value FROM counters WHERE id = 1 FOR UPDATE;
-- Increment the counter
UPDATE counters SET value = value + 1 WHERE id = 1;
COMMIT;

Is there a way to use a wildcard in a "where" statment for MySQL?

I have a query that uses a where clause. At times, this may be used and at others, I may want to omit it completely to get back all results. I can certainly write two different queries but I would like to cut down on any code that I can for simplistic reasons. Is there a way to do this in mysql?
Take a query like:
SELECT * FROM my_table WHERE id = '3'
and:
SELECT * FROM my_table
Is there a way to use the top query and still get back all records?
No, because the predicate in the first query may not actually retrieve all of the records from the table; it may use an index so that it only has to obtain the specific record(s) the query needs to return.
If you wanted to keep a predicate of that same form but still return all of the results, you would need to do something like this:
where id = 3 or id <> 3
or this:
where id = id
Note that to either of these, you'll have to add or id is null if id can be null.
If you just want to have a predicate in your query, this will suffice:
where 1
but this is just redundant, and you may as well just leave the predicate out.
More food for thought...
I notice you quoted the '3'. If your ids are char data you could use the LIKE string comparison operator.
For a single value
SELECT * FROM my_table WHERE id LIKE '3'
For all values
SELECT * FROM my_table WHERE id LIKE '%'
Won't give you any values with NULL id though.
If I understand your question correctly, then YES
SELECT * FROM my_table WHERE 1=1
If you're building the SQL query as you go along, and you decide at the last minute that you want to negate/ignore the "WHERE" part of your query, you can append OR 1 to your where-clause. Remember that logically, X OR TRUE is true for all X.
sqlite> SELECT id FROM moz_downloads WHERE id < 405 LIMIT 10;
80
403
404
sqlite> SELECT id FROM moz_downloads WHERE id < 405 OR 1 LIMIT 10;
80
403
404
405
407
408
409
410
411
412
Note that I had to stick a LIMIT 10 in there to not get too many results for the demonstration, but the second statement's where-clause is id < 405 or 1.
It depends on the application, but you may or may not generate your queries at runtime. Some queries will always be the same, like SELECT * FROM recent_files, but some queries will be like generated on-the-fly. In the latter case, you might have something like
something = make_safe_for_sql(get_something_from_user())
query = "SELECT * FROM data WHERE something=" + something
if should_ignore_something:
query += " OR 1"
database.execute(query)
Note: Depending on your SQL engine, you might need to do OR 1=1 to evaluate to a boolean true.
Your question is dubious. You are really saying that when there is no id==3 all entries should be returned. You can do that easily if you pull all entries and then sort them out using php:
$sql = mysql_query("SELECT * FROM my_table");
while($row = mysql_fetch_array($sql) {
if($row['id']==3)
// do something
}
But as the table grows this will put an enormous stress on the database. You should go with the multiple query and enforce some kind of limit on the second query.
// try to get id == 3
SELECT * FROM my_table
// if id == 3 returns 0 results
SELECT * FROM my_table LIMIT 5
Hope it helps!
You'd have to be using dynamic SQL, like
"SELECT * FROM my_table WHERE id " &
qualifier
Then set qualifier to "= '3'" or to "1".