I have a table with 60 boolean (TINYINT(1)) searcheable columns. User has possibility of using any subset of the given columns as search condition. Based on that I cannot create a good index for my needs. I was wondering if I can create another column (concat_col) of type BIT(60) that would be concatenation of the searchable columns, i.e.
Table_A:
id |col1|col2|...|col60|concat_col
9999 | 1 | 0 |...| 1 |10...1
I could then create a good index for it (on concat_col) but there is one problem - how do I create a query for it?
Please see this example written in pseudo code:
Standard version (This would obviously work fine):
SQL = SELECT * FROM Table_A WHERE col1=1 AND col60=1
My version ('*' is wildcard because it is not '1' neither '0'):
SQL = SELECT * FROM Table_a WHERE concat_col = '1*...1'
Is there any possibility of solving this problem effectively? Thank you very much for your help!
try with:
SQL = SELECT * FROM Table_a WHERE concat_col REGEXP '^1[0-9a-zA-Z]{58}1$'
Related
I have a Mysql database that contains some category ids on it which stores comma-separated values on a table.
sql table view
By using select * from style where categories like '%8,%'; it returns all the values end with 8. For example, if the table rows have two values like 8 and 148 it returns both rows. But I want to get only the rows that contain 8. How to do it
Storing multiple values in a single column is a denormalised design that will almost always cause you problems. However you need to add commas to both sides and compare:
select *
from Style
where concat(',',Categories,',') like '%,8,%';
Like everyone else: normalize your data. But if you can't mySQL supports find_in_set() for set datatypes which this appears to be.
DEMO dbfiddle.uk
DOC LINK: Find_in_set()
DOC LINK: SET data type
SQL
With CTE as (SELECT 'T-Shrits' as baseCategory, '8,21,75,87,148' categories UNION ALL
SELECT 'T-Shrits' as baseCategory, '8,21,75,87,148' categories UNION ALL
SELECT 'T-Shrits - Long Sleeve' as baseCategory, '8,21,75,87,148,92' categories UNION ALL
SELECT 'T-Shrits' as baseCategory, '21,75,87,100,148' categories)
SELECT * FROM CTE where find_in_set(8,categories) >0
OR we can use a boolean evaluation and eliminate the > 0
SELECT * FROM CTE where find_in_set(8,categories)
Giving us:
+------------------------+-------------------+
| baseCategory | categories |
+------------------------+-------------------+
| T-Shrits | 8,21,75,87,148 |
| T-Shrits | 8,21,75,87,148 |
| T-Shrits - Long Sleeve | 8,21,75,87,148,92 |
+------------------------+-------------------+
Notes
Find_in_set() returns the Returns a value in the range of 1 to N in the pseudo array of the value being searched. We need to ensure the result is greater than 0 (or treat it as a Boolean) in order for the searched value to "exist" within a record column.
The engine didn't return my 4th union value in CTE because it doesn't have an "alone" 8 value
If we searched for just 100 it would return that last record.
This function comes at a cost of performance on large datasets; which if data was normalized and indexed, you wouldn't have.
So why does this exit? For small enumerated lists or properties. It's still not ideal but if you have just a few using it "can" make sense. but in a very limited use case and often is missused.
This design violates 3rd normal form. Which is why most RDBMS designs cringe when it's brought up as it's not scalable.
as to why people are up in arms about multi value columns: Read this or This
You can also use rlike and in fact it is much better than like as it has much more options.
* = repetition of what is in front of it zero or more times
. = Equivalent to any character including none
^ = Anchor start (Forces that begins with ...)
$ = final anchor (forces it to end with ....)
[ ] = [ RST ] Contain an R or S or T but only one
[^] = DENY IT
And many more options
select * from style where concat(',',categories,',') rlike '*,8,*';
Is there a way to get a column name from table where all values in this column are the same!
Example! IF i would there would be a such a code it would return answer 'Works'
Table1
ID Name Works
1 Andre Yes
2 John Yes
3 Stewart Yes
I don't know if the columns of the table are known. If not, you could be able to get them by:
desc Table1;
or if you are using higher version of MySQL, you could use:
select column_name from information_schema.columns where table_schema='your_schema' and table_name='Table1';
Then you try the following statement with parameters #column being replaced with the column names retrieved from the above statement:
select count(*) from (select count(*) as c from Table1 as t group by t.#column) as sub;
If the result is 1, the column is what you want. The result means how many distinct values this column has.
I suppose you will have to use a kind of programming language or stored procedure. You are not likely being able to achieve that with one single SQL statement.
I'm not sure if it's possible to run from MySQL itself but you can do this from your scripting engine.
You can run a loop on each column and do a query:
SELECT
COUNT(DISTINCT column_name)
FROM table_name;
And see you get 1 record in the results
I would like to SELECT * FROM table where the first column is equal to a variable. It supposed that I don't know the column name.
I know I can do something like
SELECT * FROM table WHERE column_id = 1
But I can't compare the data.
How can I do that?
I found some solution with T-SQL but it doesn't interest me.
To be more accurate :
I'm developing an administration panel in my website where the "super" admin can directly modify the database. For that I can select a table and edit this table. But to do that, I'm using an only PHP script which showing all tables, we can select one and the script show all rows in the selected table. After that you select a row and you are redirected to a page where the problem is. This page can receive any table with only one row, so I want to SELECT the data contained in this row.
Images to understand:
The first one shows the tables.
The second shows the rows of a selected table.
The third shows (normally) the data of 1 row but in this picture we can see data of many rows.
selecto http://imageshack.us/g/135/selecto.png
I found a solution :
Try to explain:
First : I selected all form the specific table which was posted
$query="SELECT * FROM ".$_POST['table']."";
$result=mysql_query($query);
Second: I attributed to a variable the column name (which I didn't know)
while($fields=mysql_fetch_array($result))
{
$col = mysql_field_name($result,0);
$nb++;
}
Third: I selected data from the table where $col = id of the row
$sql = "SELECT * FROM ".$_POST['table']." WHERE ".$col."=".$_GET['idRow']."";
$result1=mysql_query($sql);
If you know how many columns there are, you could use this little trick here:
SELECT *
FROM (
SELECT null x1, null x2, ..., null xn
WHERE 1 = 0
UNION ALL
SELECT * FROM my_table
) t
WHERE t.x1 = something
In other databases than MySQL, renaming "unknown" columns would be even simpler, e.g. in PostgreSQL you could rename only the first column like this:
SELECT * FROM my_table t(x) WHERE x = something
If you don't know anything about the table
... you can quickly query the information_schema first:
SELECT column_name
FROM information_schema.columns
WHERE table_name = :my_table
AND ordinal_position = 1
A note on SQL injection
Please don't, DON'T do this. EVER:
$query="SELECT * FROM ".$_POST['table']."";
I've recently written an article about SQL injection. Every single vulnerability like yours will allow any script kiddie to dump your database, or worse.
The solution is to sanitize your input first. Ideally, you'll maintain a catalog of allowed table strings, compare your $_POST variable with those, and then concatenate the pre-defined table string into your SQL statement, NOT the user input.
I think you can use SHOW CREATE TABLE table_name to fetch the schema of the table. After that, you should already know every column.
In PHP you could do something like:
$col = 'users';
mysql_query("SELECT * FROM table WHERE $col = $something");
I am trying to query a table in mysql based on the length of a string in a specific column. I know mysql has a function called LENGTH(), but that returns the length of the string. I want to be able to pull data based on the result of the LENGTH() function.
Example:
SELECT * table WHERE LENGTH(word) = 6
of course that does not work. I read through http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function%5Flength but could not find anything to help me.
yes I could make something in PhP to accomplish this, but I would like to do it at the query level.
Any help?
Try:
SELECT *
FROM table
WHERE LENGTH(RTRIM(word)) = 6
I believe you wanted to use query SELECT * FROM tableName WHERE LENGTH(word) = 6; (assuming that the word is name of column in tableName).
This is very unfortunate solution on large tables, you should create new column and use UPDATE tableName SET wordLength = LENGTH( word).
A bit of background
I'm running mySQL on a mac
I have a few databases setup that have been working okay
I have recently created a new table from a sqlDump from another server.
I am having an issue with new rows that equal = a value that I know exists
e.g. Table setup
id=1 name='dave' - already exists in database
id=2 name='john' - I add a new row
Following are the sql I tried with results...
Select * from tablename where id=1 -- I get the correct Dave result.
Select * from tablename where `name` = 'dave' -- I get the correct Dave result.
Select * from tablename where id=2 -- I get the correct John result.
Select * from tablename where `name` like 'joh%' -- I get the correct John result.
Select * from tablename where `name` = 'john' -- (No result!) eek!
Anyone seen this before? it's in the database but a direct match on the name field is not yielding a result.
Thanks in advance
M
One possibility: there could be a trailing space after 'john' in the name column.
One way to check that:
select `name`,char_length(`name`), char_length('john')
from tablename
where id = 2
An easy way to not have to deal with that problem would be to trim your input (if you don't expect to ever have preceding or trailing white space.
In that case you could have a query like:
Select * from tablename where trim(`name`) = trim('john')
I agree with the comments on your question, that it is most likely a hidden space or something similar. If you include the column definitions so we can check the data that your using with the types we could help more. Remove the entry and and retry with a different name other than john and see if you can replicate the problem.