How do I create a MySQL query using an array? - mysql

I need to take an array and use it for a MySQL query.
I tried looking for methods but all of them seem to be related to PHP arrays and not Ruby.
For example, I have terms = ['genetics', 'elderly', 'health'] and I want to use:
con.query "SELECT col1 FROM data1 WHERE MATCH (col2) AGAINST (terms)"
Is this possible?

You can just join your terms in your against clause:
terms = ['genetics' , 'elderly', 'health']
con.query "SELECT col1 FROM data1 WHERE MATCH col2 AGAINST ('#{terms.join(' ')}')"
Note that using match/against will almost certainly be more performative than using a series of like clauses. See this StackOverflow answer for more information: Which SQL query is better, MATCH AGAINST or LIKE?.
Check out the MySQL documentation for more information on full text searching (including possible operators): http://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html.

I'd highly recommend looking into an ORM, such as Sequel, which makes it very easy to generate the proper query in a DBM independent way.
It allows us to use arrays and hashes conveniently. Here's an example using an array to generate the "where" clause in SQL:
my_posts = posts.where(:category => ['ruby', 'postgres', 'linux'])
# WHERE category IN ('ruby', 'postgres', 'linux')
That particular example is part of the "Filtering Records" section.
In a comment, the OP said:
col2 is text with each row having a paragraph, not just one word.
Then you want a LIKE or regex clause that allows each word to be tested. See the "String search functions" section of "Dataset Filtering " for how Sequel allows you to search inside strings.
The code would be something like:
data1.select(:col1).where(Sequel.like(:col2, terms.map{ |t| "%#{ t }%" } ))
which would generate something like:
SELECT col1 FROM data1 WHERE ((col2 LIKE '%genetics%') OR (col2 LIKE '%elderly%') OR (col2 LIKE '%health%'))

Related

Checking multiple columns for a concatenated match MySQL

Hi i've hit a problem with my SQL queries, i have a table that contains 3 columns, one for vehicle brands, one for models and one for model versions.
So my data is split like
BRAND || MODEL || MODEL VERSION
RENAULT || R4 || R4 1.1 GTL
I've been asked to replace our current dropdown system with an input to make it easier for users to select their vehicle.
I'm using jQuery Autocomplete and my query looks something like this.
SELECT DISTINCT CONCAT (brand, ' ', model, ' ', version) as data from vehicles WHERE brand LIKE '%Golf%' OR model LIKE '%Golf%' OR version LIKE '%Golf%' LIMIT 5
So far so good, this will output "RENAULT R4 R4 1.1 GTL" if i type in "RENAULT"... the problem here comes when the user inserts something like Renault R4 instead of just "Renault"
As they've included the Model name as well as the Brand then it doesn't really match any of my columns in the Database and my Ajax call returns no results.
I need to query the actual result set from that concat instead so that anything the users type in will match the results, but i have no idea how i can do this.
In desperation i tried to type where data LIKE '%RENAULT R4%' but as expected this also doesn't work... What can i do in this situation? Any help would be appreciated.
Easy and slow way: Split the string by spaces and ask for each word.
SELECT ...
WHERE
(brand LIKE '%Renault%' OR model LIKE '%Renault%' OR version LIKE '%Renault%')
AND (brand LIKE '%R4%' OR model LIKE '%R4%' OR version LIKE '%R4%')
LIMIT 5
Keep in mind, that query like this one does not allow use of any index, so it is very slow.
The more complicated, but much faster implementation is to use fulltext index. You need recent version of MySQL (5.6 or newer); older versions support fulltext only on MyISAM tables which are not really a database.
CREATE FULLTEXT INDEX idx ON vehicles(brand, model, version);
SELECT ... FROM vehicles
WHERE MATCH(brand, model, version) AGAINST('Renault R4')
LIMIT 5;
(Query not tested, but you should get the idea.)
I can only think of this one, but I believe there are better ways to do it.
OR CONCAT (brand, ' ', model, ' ', version) LIKE '%RENAULT R4%'

MySQLi PHP using OR and AND

Sorry about the title, I wasn't sure how to word it
I'm wanting to make a instant messaging system with PHP (I've done ajax for it) but I'm not sure how to get the query, I'm wanting something like this:
"SELECT * FROM messages WHERE user='$to' AND sender='$username' OR user='$username' AND sender='$to'"
Does anyone know if this is possible? Or a mysqli_fetch_array for two invididual queries on the same variable.
You can use parenthesis to use multiple operations to work as single operation in query. This is the typical approach anyway, and very useful for using multiple AND, OR operators in a query.
For you case, query should be like
"SELECT * FROM messages WHERE ( user='$to' AND sender='$username' ) OR ( user='$username' AND sender='$to' )"
Notice that tho we used 4 conditions, but with parenthesis we shrieked it into 2 separate conditions and ultimately one OR operation in the query.
Some good reading about this stuff at this article in case you want to dig it more

What is the "Rails Way" of doing a query with an OR clause using ActiveRecord?

I'm using Rails 3 with a MySQL database, and I need to programmatically create a query like this:
select * from table where category_name like '%category_name_1%'
OR category_name like '%category_name_2%'
(...snip...)
OR category_name like '%category_name_n%'
Given the table size and the project scope (500 rows at most, I think), I feel that using something like thinking sphinx would be overkill.
I know I could simply do this by writing the query string directly, but wanted to know if there's an ActiveRecord way to do this. There's no mention of this on the official guide, and I've been googling for a long while now, just to end empty-handed :(
Also, is there a reason (maybe a Rails reason?) to not to include the OR clause?
Thanks!
Assuming you have an array names with category names:
Model.where( names.map{"category_name LIKE ?"}.join(" OR "),
*names.map{|n| "%#{n}%" } )
you should google first, there is already an answer.
Look here and then here
and you'll get something like this:
accounts = Account.arel_table
Account.where(accounts[:name].matches("%#{user_name}%").or(accounts[:name].matches("%#{user_name2}%")))
If you look at the guide, they have examples that can easily be modified to this:
Client.where("orders_count = ? OR locked = ?", params[:orders], false)
Mysql has a regexp function now that can clean things up a bit, assuming there's no regex metachars in your category names:
Table.where "category_name regexp '#{names.join('|')}'"

Query on custom metadata field?

This is a request from my client to tweak an existing Perl script. However, it is the actual database structure on their end that confuses me.
The requirement looks pretty simple:
only pull records where _X begins with 1, 2, or 9.
However, the underlying database is not that simple, here is the guideline from their DBA:
"_X is a custom metadata field. The database stores this data in rows, not columns, within the customData table. In order to query the custom data table in an efficient manner you need to know the Field_ID for the custom field you get that from the fielddef table:
SELECT Field_ID FROM FieldDef WHERE Name = "_X";
This returns:
10012
"Now you can query CustomData. For example:
SELECT Record_ID FROM CustomData where Field_ID="10012" AND StringValue="2012-04";
He also suggests that in my case, probably it would be:
"SELECT Record_ID FROM CustomData where Field_ID="10012" AND (StringValue LIKE '1%' || StringValue LIKE '2%' || StringValue LIKE '9%')
The weird thing is that the existing Perl script doesn't contain anything like "Select Record_ID FROM" but all like "SELECT StringValue FROM".
So that is why I am very confused here: What is "store in rows, not in columns"? Why first query the Field_ID table then CustomData? I would not be able to communicate with any of them during this weekend but really wish to get some idea on the whole thing, hope experts can help me a little on sorting out the whole structure.
More info(Table schema):
http://pastebin.com/ZiDTCCC0
The existing perl script:(focus on lines 72-136)
http://pastebin.com/JHpikTeZ
Thanks in advance.
What they seem to be using is some kind of Entity-Attribute-Value model, with the entities stored as ints and explained in another table (FieldDef).
You explained pretty well how you queried it (although you can do it in one query, with a join or a subquery), and your problem seems to be that you don't know how the Perl script does it. Unfortunately, without us seeing the Perl script, we can't either :]

Combine 'like' and 'in' in a SqlServer Reporting Services query?

The following doesn't work, but something like this is what I'm looking for.
select *
from Products
where Description like (#SearchedDescription + %)
SSRS uses the # operator in-front of a parameter to simulate an 'in', and I'm not finding a way to match up a string to a list of strings.
There are a few options on how to use a LIKE operator with a parameter.
OPTION 1
If you add the % to the parameter value, then you can customize how the LIKE filter will be processed. For instance, your query could be:
SELECT name
FROM master.dbo.sysobjects
WHERE name LIKE #ReportParameter1
For the data set to use the LIKE statement properly, then you could use a parameter value like sysa%. When I tested a sample report in SSRS 2008 using this code, I returned the following four tables:
sysallocunits
sysaudacts
sysasymkeys
sysaltfiles
OPTION 2
Another way to do this that doesn't require the user to add any '%' symbol is to generate a variable that has the code and exceute the variable.
DECLARE #DynamicSQL NVARCHAR(MAX)
SET #DynamicSQL =
'SELECT name, id, xtype
FROM dbo.sysobjects
WHERE name LIKE ''' + #ReportParameter1 + '%''
'
EXEC (#DynamicSQL)
This will give you finer controller over how the LIKE statement will be used. If you don't want users to inject any additional operators, then you can always add code to strip out non alpha-numeric characters before merging it into the final query.
OPTION 3
You can create a stored procedure that controls this functionality. I generally prefer to use stored procedures as data sources for SSRS and never allow dynamically generated SQL, but that's just a preference of mine. This helps with discoverability when performing dependency analysis checks and also allows you to ensure optimal query performance.
OPTION 4
Create a .NET code assembly that helps dynamically generate the SQL code. I think this is overkill and a poor choice at best, but it could work conceivably.
Have you tried to do:
select * from Products where Description like (#SearchedDescription + '%')
(Putting single quotes around the % sign?)
Dano, which version of SSRS are you using? If it's RS2000, the multi-parameter list is
not officially supported, but there is a workaround....
put like this:
select *
from tsStudent
where studentName like #SName+'%'
I know this is super old, but this came up in my search to solve the same problem, and I wound up using a solution not described here. I'm adding a new potential solution to help whomever else might follow.
As written, this solution only works in SQL Server 2016 and later, but can be adapted for older versions by writing a custom string_split UDF, and by using a subquery instead of a CTE.
First, map your #SearchedDescription into your Dataset as a single string using JOIN:
=JOIN(#SearchedDedscription, ",")
Then use STRING_SPLIT to map your "A,B,C,D" kind of string into a tabular structure.
;with
SearchTerms as (
select distinct
Value
from
string_split(#SearchedDescription, ',')
)
select distinct
*
from
Products
inner join SearchTerms on
Products.Description like SearchTerms.Value + '%'
If someone adds the same search term multiple times, this would duplicate rows in the result set. Similarly, a single product could match multiple search terms. I've added distinct to both the SearchTerms CTE and the main query to try to suppress this inappropriate row duplication.
If your query is more complex (including results from other joins) then this could become an increasingly big problem. Just be aware of it, it's the main drawback of this method.