Sequence restrictions of SELECT statement - sql

In my table I have a column of type nVarchar or nText
Suppose value of a this col is like this '... xxx yyy zzz ...'
I use SELECT to search table with this column
SELECT * FROM tbl_name WHERE col_name like '%xxx yyy%'
Since the I can't force users to enter words with my sequence I want to give same result with this query too:
SELECT * FROM tbl_name WHERE col_name like '%yyy xxx%'

It looks to me like you might want to consider normalizing your table. Specifically, if "yyy xxx" is the same as "xxx yyy", you're storing an array (or list or whatever you want to call it) in one column, which breaks first normal form. Normalize it so that each of those atoms (i.e. "xxx", "yyy") are stored separately and are related back to your original record. Then it's almost trivial to do the kind of thing you're looking to do.

You have to tokenize the user input into separate words inside your application code (not in sql) and then construct queries like
SELECT * FROM tbl_name WHERE
(col_name like '%yyy%') AND (col_name like '%xxx%') AND ...

Your best bet is to use both criteria, and "OR".
SELECT *
FROM tbl_name
WHERE (col_name like '%xxx yyy%')
OR (col_name like '%yyy xxx%');

Related

How to select all columns not containing a certain substring in Postgresql?

If I have a table with column names like that:
name,
name_raw,
item,
item_raw,
message,
message_raw
...
... etc.
How can I select every column that does not end with _raw dynamically?
Is something like this:
SELECT
[SOME REGEX LOGIC HERE]
FROM
mytable
or similar possible?
If you have so many columns that you cannot write a (static) query, you probably have to change the schema of your db.
If you cannot change the schema, here's a quick and dirty solution that utilizes postgresql's JSON capabilities. It does not return a traditional table with multiple columns, instead it returns a single column that contains json objects which contain all the columns from the original table whose name ends with _raw.
SELECT (
SELECT json_object_agg(key,value)
FROM json_each(to_json(t))
WHERE key ~ 'raw$'
) FROM mytable;
The idea is convert every row from mytable to a JSON object and then use JSON functions to filter the members of the object.
Use the information schema e.g.
SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'my_schema'
AND table_name = 'mytable'
AND NOT column_name LIKE '%\_raw'
note because the underscore itself is a query wildcard it needs to be "escaped"

Using string values inside "IN" in Informix

In database table in Informix I have columns like this:
Table name is MYTABLE
key 1234
value 'POCO','LOCD',MACD'
Now I want to use this in a query like this
select * from table where symbol in (select value from MYTABLE where key='1234');
But this query is not working as value is stored as char and
output of select value from MYTABLE where key='1234' would be something like
"'POCO','LOCD',MACD'"
Is there a way to make this work. I want to achieve this in a single query.
Please suggest a better approach.
You cannot interpolate values like that. The database optimiser cannot be expected to know that value is going to return a string that looks like a list, which is to be interpreted in a list context.
Since you ask for a better approach…
That design breaks numerous fundamental rules about how databases should be structured. At a minimum, the 'value' column should be a COLLECTION data type, so that its role as a list of values is properly articulated. Personally I would create a standard, relational bridging table:
MYTABLE
key col1 col2
1234 .. ..
MYVALUE
key value
1234 POCO
1234 LOCD
1234 MACD
This is not the easy way out suggested by others, but it is the right answer.

MySQL question about "reverse LIKEs"

Well given I have a value I want to check for potential matches in a database (in one varchar field) so I write something like:
SELECT * FROM table WHERE column LIKE "%value%"
Which will work if the value is something like "test" and the column has a value of "this is a test" however if it is reversed then I will not get a match I have tried things along the lines of:
SELECT * FROM table WHERE CONCAT("%",column,"%") LIKE "value"
but don't know exactly how to phrase this to Google to get a response I need, please help!
You can reverse a like statement. Just using the same syntax as a regular like query:
select
*
from
table
where
'value' like concat('%', column, '%')
Of course, if you felt wild and crazy, you could also use instr:
select * from table where instr('value', column) > 0
I don't know which one is faster, since I don't have a MySQL instance to test against, but it's worth trying both to see which wins.
SELECT *
FROM table
WHERE 'value' LIKE CONCAT('%', column, '%')

How to implement a Keyword Search in MySQL?

I am new to SQL programming.
I have a table job where the fields are id, position, category, location, salary range, description, refno.
I want to implement a keyword search from the front end. The keyword can reside in any of the fields of the above table.
This is the query I have tried but it consist of so many duplicate rows:
SELECT
a.*,
b.catname
FROM
job a,
category b
WHERE
a.catid = b.catid AND
a.jobsalrange = '15001-20000' AND
a.jobloc = 'Berkshire' AND
a.jobpos LIKE '%sales%' OR
a.jobloc LIKE '%sales%' OR
a.jobsal LIKE '%sales%' OR
a.jobref LIKE '%sales%' OR
a.jobemail LIKE '%sales%' OR
a.jobsalrange LIKE '%sales%' OR
b.catname LIKE '%sales%'
For a single keyword on VARCHAR fields you can use LIKE:
SELECT id, category, location
FROM table
WHERE
(
category LIKE '%keyword%'
OR location LIKE '%keyword%'
)
For a description you're usually better adding a full text index and doing a Full-Text Search (MyISAM only):
SELECT id, description
FROM table
WHERE MATCH (description) AGAINST('keyword1 keyword2')
SELECT
*
FROM
yourtable
WHERE
id LIKE '%keyword%'
OR position LIKE '%keyword%'
OR category LIKE '%keyword%'
OR location LIKE '%keyword%'
OR description LIKE '%keyword%'
OR refno LIKE '%keyword%';
Ideally, have a keyword table containing the fields:
Keyword
Id
Count (possibly)
with an index on Keyword. Create an insert/update/delete trigger on the other table so that, when a row is changed, every keyword is extracted and put into (or replaced in) this table.
You'll also need a table of words to not count as keywords (if, and, so, but, ...).
In this way, you'll get the best speed for queries wanting to look for the keywords and you can implement (relatively easily) more complex queries such as "contains Java and RCA1802".
"LIKE" queries will work but they won't scale as well.
Personally, I wouldn't use the LIKE string comparison on the ID field or any other numeric field. It doesn't make sense for a search for ID# "216" to return 16216, 21651, 3216087, 5321668..., and so on and so forth; likewise with salary.
Also, if you want to use prepared statements to prevent SQL injections, you would use a query string like:
SELECT * FROM job WHERE `position` LIKE CONCAT('%', ? ,'%') OR ...
I will explain the method i usally prefer:
First of all you need to take into consideration that for this method you will sacrifice memory with the aim of gaining computation speed.
Second you need to have a the right to edit the table structure.
1) Add a field (i usually call it "digest") where you store all the data from the table.
The field will look like:
"n-n1-n2-n3-n4-n5-n6-n7-n8-n9" etc.. where n is a single word
I achieve this using a regular expression thar replaces " " with "-".
This field is the result of all the table data "digested" in one sigle string.
2) Use the LIKE statement %keyword% on the digest field:
SELECT * FROM table WHERE digest LIKE %keyword%
you can even build a qUery with a little loop so you can search for multiple keywords at the same time looking like:
SELECT * FROM table WHERE
digest LIKE %keyword1% AND
digest LIKE %keyword2% AND
digest LIKE %keyword3% ...
You can find another simpler option in a thread here: Match Against.. with a more detail help in 11.9.2. Boolean Full-Text Searches
This is just in case someone need a more compact option. This will require to create an Index FULLTEXT in the table, which can be accomplish easily.
Information on how to create Indexes (MySQL): MySQL FULLTEXT Indexing and Searching
In the FULLTEXT Index you can have more than one column listed, the result would be an SQL Statement with an index named search:
SELECT *,MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*') as relevance FROM `documents`USE INDEX(search) WHERE MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*' IN BOOLEAN MODE) ORDER BY relevance;
I tried with multiple columns, with no luck. Even though multiple columns are allowed in indexes, you still need an index for each column to use with Match/Against Statement.
Depending in your criterias you can use either options.
I know this is a bit late but what I did to our application is this. Hope this will help someone tho. But it works for me:
SELECT * FROM `landmarks` WHERE `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE 'keyword%'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword%'

SQL set column names from another query

I'm am using MS Reporting Services to graph some data from an Oracle database. I want to name the columns in my select statement with values from another select statement. Is this possible?
Like instead of
Select Column1 As 'Test' From Table1
could I do something like
Select Column1 As (Select column2 from Table2 where Value = 1) From Table1
?
I would think you'd have to query out separately, then form the query dynamically. Interested to see if there is a different answer.
My PL/SQL's a little rusty, so what follows is more pseudocode than compilable & tested code. And this is completely off the top of my head. But if you know the specific ordinal location of the column in the table, you may try this:
columnName varchar2(50) :=
Select column_name
From all_tab_columns c
Where lower(table_name) = '<% Your Table2 Name %>' And
column_id = 9 -- The appropriate ordinal
Order By column_id;
Select Column1 As columnName From Table1;
There may be more column values drawn from "all_tab_columns" that'll help you as well. Take a look around and see.
I hope this helps.
You can query all needed column names into separate report dataset, create hidden multivalue report parameter vColumns, set dataset with columns as a parameter default values, and use it as a string array:
Parameters!vColumns(0).Value - will be the first column etc. So you can use them as a query parameters.
See Lesson 4: Adding a Multivalue Parameter