Searching for particular combinations across two columns (nvarchar) - sql-server

I am trying to search a table for entries that feature a combination of specific values across two particular columns.
I'm having no problem performing the search using one condition:
SELECT *
FROM Table
WHERE [artist_id] IN ('ID1', 'ID2', etc)
But I'd like to add a second condition, something like this:
AND WHERE [track_name] IN (NAME1', 'NAME2', etc)
A few notes:
"artist_id" and "track_name" are both formatted as nvarchar, with "track_name" taking the form of single words or phrases.
There are multiple entries for each "artist_id" and "track_name," but all combinations of the two are unique.
So, how can I combine these conditions into a single query?
Here's a snippet of the code:
SELECT *
FROM [Music].[dbo].[echonest_tracks]
WHERE [artist_id] IN ('AR03U0G1187B9B1D35', 'AR03U0G1187B9B1D35', etc)
AND [track_title] IN ('Location', 'Cape Vibes Got 'em?', 'Feeling Good (Instrumental Remix)', 'How my heart by you', etc)

I think this is what you are looking for since you are looking for combinations:
SELECT *
FROM [Music].[dbo].[echonest_tracks]
WHERE
([artist_id] = 'AR03U0G1187B9B1D35' AND [track_title] IN ('Location', 'Cape Vibes Got 'em?', 'Feeling Good (Instrumental Remix)')
OR
([artist_id] = 'AR03U0G1187B9B1D35' AND [track_title] IN ('How my heart by you', etc))

You are almost there.
SELECT *
FROM Table
WHERE [artist_id] IN ('ID1', 'ID2', etc)
AND [track_name] IN ('NAME1', 'NAME2', etc)
should do it.
As for the single quote within a query string, see this answer:
How do I escape a single quote in SQL Server?
You need to double up a single quote to have it within a query string.

Related

SQL database/column name convention + language code

Usually in master tables we have a name column and it is usually in English.
But what is the best column naming convention if we have it in different languages. Is en_name better than name_en?
( keep in mind, i will use JPA and entities). For now, I will need the following columns:
en_name for English.
ar_name for Arabic.
fr_name for French.
de_name for German.
Also, which is better to use the two letters ISO 639-1 codes or three letters ISO 639-2 Code?
It depends on what you need. If you need just a separate columns to store in DB name translations, I'll recommend to use name_de, name_en ..., but it's just my preference, it's easy to read and understand purpose of column.
But think about filtering (searching). If you prefere this aprouch with additional columns in the same table, you will need to add some kind of switch in query (stored procedure) to search name for specific language - for English you need to search in name_en, German - name_de. So I could recommend solution with separate table for localization with columns id, [master_table]_id, language_code and text (or name).
For example, there is a table item with columns idand name.
I would create table item_localization with columns id, item_id, language_code and text.
So for row (1, "name") in table item in item_localization will be (1, 1, "en", "name-en"), (1, 2, "de", "name-de").
I prefere to store in master table English name and also duplicate it in localization table. In this case it's easy to filter by localized name, something like
select item.*
from item
join item_localization on item_localization.item_id = item.id
where item_localization.language_code = "de" and item_localization.text like "%some_text%"
But it's just my experience and thoughts.

MS Access, use query name as field default value

My department uses a software tool that can use a custom component library sourced from Tables or Queries in an MS Access database.
Table: Components
ID: AutoNumber
Type: String
Mfg: String
P/N: String
...
Query: Resistors
SELECT Components.*
FROM Components
WHERE Components.Type = "Resistors"
Query: Capacitors
SELECT Components.*
FROM Components
WHERE Components.Type = "Capacitors"
These queries work fine for SELECT. But when users add a row to the query, how can I ensure the correct value is saved to the Type field?
Edit #2:
Nope, can't be done. Sorry.
Edit #1:
As was pointed out, I may have misunderstood the question. It's not a wonky question after all, but perhaps an easy one?
If you're asking how to add records to your table while making sure that, for example, "the record shows up in a Resistors query if it's a Resistor", then it's a regular append query, that specifies Resisitors as your Type.
For example:
INSERT INTO Components ( ID, Type, Mfg )
SELECT 123, 'Resistors', 'Company XYZ'
If you've already tried that and are having problems, it could be because you are using a Reserved Word as a field name which, although it may work sometimes, can cause problems in unexpected ways.
Type is a word that Access, SQL and VBA all use for a specific purpose. It's the same idea as if you used SELECT and FROM as field or table names. (SELECT SELECT FROM FROM).
Here is a list of reserved words that should generally be avoided. (I realize it's labelled Access 2007 but the list is very similar, and it's surprisingly difficult to find an recent 'official' list for Excel VBA.)
Original Answer:
That's kind a a wonky way to do things. The point of databases is to organize in such a way as to prevent duplication of not only data, but queries and codes as well
I made up the programming rule for my own use "If you're doing anything more than once, you're doing it wrong." (That's not true in all cases but a general rule of thumb nonetheless.)
Are the only options "Resistors" and "Capacitors"? (...I hope you're not tracking the inventory of an electronics supply store...) If there are may options, that's even more reason to find an alternative method.
To answer your question, in the Query Design window, it is not possible to return the name of the open query.
Some alternative options:
As #Erik suggested, constrain to a control on a form. Perhaps have a drop-down or option buttons which the user can select the relevant type. Then your query would look like:
SELECT * FROM Components WHERE Type = 'Forms![YourFormName]![NameOfYourControl]'
In VBA, have the query refer to the value of a variable, foe example:
Dim TypeToDel as String
TypeToDel = "Resistor"
DoCmd.RunSQL "SELECT * FROM Components WHERE Type = '" & typeToDel'"
Not recommended, but you could have the user manually enter the criteria. If your query is like this:
SELECT * FROM Components WHERE Type = '[Enter the component type]'
...then each time the query is run, it will prompt:
Similarly, you could have the query prompt for an option, perhaps a single-digit or a code, and have the query choose the the appropriate criteria:
...and have an IF statement in the query criteria.
SELECT *
FROM Components
WHERE Type = IIf([Enter 1 for Resistors, 2 for Capacitors, 3 for sharks with frickin' laser beams attached to their heads]=1,'Resistors',IIf([Enter 1 for Resistors, 2 for Capacitors, 3 for sharks with frickin' laser beams attached to their heads]=2,'Capacitors','LaserSharks'));
Note that if you're going to have more than 2 options, you'll need to have the parameter box more than once, and they must be spelled identically.
Lastly, if you're still going to take the route of a separate query for each component type, as long as you're making separate queries anyway, why not just put a static value in each one (just like your example):
SELECT * FROM Components WHERE Type = 'Resistor'
There's another wonky answer here but that's just creating even more duplicate information (and more future mistakes).
Side note: Type is a reserved word in Access & VBA; you might be best to choose another. (I usually prefix with a related letter like cType.)
More Information:
Use parameters in queries, forms, and reports
Use parameters to ask for input when running a query
Microsoft Access Tips & Tricks: Parameter Queries
 • Frickin' Lasers

one function or many for doing two-way lookups on multi-column junction table?

In SQL Server, we have a junction table associating our property IDs with IDs (text or numeric) of the same properties in several external databases (with sentinel value -1 or '-1' for no link):
SEPID SEPCODE AEID MRIID ABSID PEDID
2087 '140800' 26077 '140800' '-1' 3162
2088 '140900' -1 '140900' '-1' 3167
2089 'F21610' 25744 '-1' '-1' 3184
2090 '15402' -1 '-1' '-1' 3185
2094 '141200' 26085 '141200' '83296' 3198
As databases and business needs grow, we write new specific functions to translate one set of IDs to another, taking a comma-separated string list of input IDs and returning either a table of output IDs or another comma-separated list of output IDs, with different use cases for the table-valued (TVF) vs scalar-valued (SVF) functions. For example (using hard-coded rather than the normal programmatically-managed ID lists):
SELECT * FROM dbo.tvf_SepIdsToAbsIds('2088,2090,2094')
SELECT * FROM dbo.tvf_MriInfo(dbo.svf_AeIds2MriIds('26077,25744'))
would return:
ABSID
'-1'
'-1'
'83296'
and
MRIID NAME ETC...
'140800' 'Foo' ...
I'm wondering if there is a sensible, practical, reasonably performant way to replace these proliferating specific functions with a single generic TVF and SVF that would take two column names and a list of IDs:
SELECT * FROM dbo.tvf_Ids('SEPID', '2088,2090,2094', 'ABSID')
SELECT * FROM dbo.MriInfo(dbo.svf_Ids('AEID', '26077,25744', 'MRIID'))
Is it possible? Does it require dynamic SQL? Do the sometimes-text/sometimes-numeric external IDs complicate things greatly? Is it worth the struggle? Dynamic SQL always feels a bit dodgy and in this case I'm not even sure how to write it.
If I understand your question you have a number of databases each mastering a set of IDs. In you chosen database you relate some\all of these with local data. You then want a way of translating between the local\remote IDS.
You could use Synonyms to point to the database and then a view to consume your synonym.
So you would have
Select *
from MyNewView
and in your MyNewView
Select *
from MyNewSynonym s
inner join Mytable.ABSID = s.ABSID
Your local data just looks at the view and doesn't know anything about the different databases or any particular conversion issues. Its all hidden in the Synonym and view.
Not really sure why you are using TVFs but they are better than using SVFs which you definitely want to avoid for performance reasons. Even better if you can hide it in a view as it may give you indexing advantages.
As for splitting strings and converting them to a rowset, you can use a number of methods to do this. Including a TVF, CLR function or some horrid looping. There a number of examples to assist out there. You then just join the result in with the results from your view above.

Selective PostgreSQL database querying

Is it possible to have selective queries in PostgreSQL which select different tables/columns based on values of rows already selected?
Basically, I've got a table in which each row contains a sequence of two to five characters (tbl_roots), optionally with a length field which specifies how many characters the sequence is supposed to contain (it's meant to be made redundant once I figure out a better way, i.e. by counting the length of the sequences).
There are four tables containing patterns (tbl_patterns_biliteral, tbl_patterns_triliteral, ...etc), each of which corresponds to a root_length, and a fifth table (tbl_patterns) which is used to synchronise the pattern tables by providing an identifier for each row—so row #2 in tbl_patterns_biliteral corresponds to the same row in tbl_patterns_triliteral. The six pattern tables are restricted such that no row in tbl_patterns_(bi|tri|quadri|quinqui)literal can have a pattern_id that doesn't exist in tbl_patterns.
Each pattern table has nine other columns which corresponds to an identifier (root_form).
The last table in the database (tbl_words), contains a column for each of the major tables (word_id, root_id, pattern_id, root_form, word). Each word is defined as being a root of a particular length and form, spliced into a particular pattern. The splicing is relatively simple: translate(pattern, '12345', array_to_string(root, '')) as word_combined does the job.
Now, what I want to do is select the appropriate pattern table based on the length of the sequence in tbl_roots, and select the appropriate column in the pattern table based on the value of root_form.
How could this be done? Can it be combined into a simple query, or will I need to make multiple passes? Once I've built up this query, I'll then be able to code it into a PHP script which can search my database.
EDIT
Here's some sample data (it's actually the data I'm using at the moment) and some more explanations as to how the system works: https://gist.github.com/823609
It's conceptually simpler than it appears at first, especially if you think of it as a coordinate system.
I think you're going to have to change the structure of your tables to have any hope. Here's a first draft for you to think about. I'm not sure what the significance of the "i", "ii", and "iii" are in your column names. In my ignorance, I'm assuming they're meaningful to you, so I've preserved them in the table below. (I preserved their information as integers. Easy to change that to lowercase roman numerals if it matters.)
create table patterns_bilateral (
pattern_id integer not null,
root_num integer not null,
pattern varchar(15) not null,
primary key (pattern_id, root_num)
);
insert into patterns_bilateral values
(1,1, 'ya1u2a'),
(1,2, 'ya1u22a'),
(1,3, 'ya12u2a'),
(1,4, 'me11u2a'),
(1,5, 'te1u22a'),
(1,6, 'ina12u2a'),
(1,7, 'i1u22a'),
(1,8, 'ya1u22a'),
(1,9, 'e1u2a');
I'm pretty sure a structure like this will be much easier to query, but you know your field better than I do. (On the other hand, database design is my field . . . )
Expanding on my earlier answer and our comments, take a look at this query. (The test table isn't even in 3NF, but the table's not important right now.)
create table test (
root_id integer,
root_substitution varchar[],
length integer,
form integer,
pattern varchar(15),
primary key (root_id, length, form, pattern));
insert into test values
(4,'{s,ş,m}', 3, 1, '1o2i3');
This is the important part.
select root_id
, root_substitution
, length
, form
, pattern
, translate(pattern, '12345', array_to_string(root_substitution, ''))
from test;
That query returns, among other things, the translation soşim.
Are we heading in the right direction?
Well, that's certainly a bizarre set of requirements! Here's my best guess, but obviously I haven't tried it. I used UNION ALL to combine the patterns of different sizes and then filtered them based on length. You might need to move the length condition inside each of the subqueries for speed reasons, I don't know. Then I chose the column using the CASE expression.
select word,
translate(
case root_form
when 1 then patinfo.pattern1
when 2 then patinfo.pattern2
... up to pattern9
end,
'12345',
array_to_string(root.root, '')) as word_combined
from tbl_words word
join tbl_root root
on word.root_id = root.root_id
join tbl_patterns pat
on word.pattern_id = pat.pattern_id
join (
select 2 as pattern_length, pattern_id, pattern1, ..., pattern9
from tbl_patterns_biliteral bi
union all
select 3, pattern_id, pattern1, pattern2, ..., pattern9
from tbl_patterns_biliteral tri
union all
...same for quad and quin...
) patinfo
on
patinfo.pattern_id = pat.pattern_id
and length(root.root) = patinfo.pattern_length
Consider combining all the different patterns into one pattern_details table with a root_length field to filter on. I think that would be easier than combining them all together with UNION ALL. It might be even easier if you had multiple rows in the pattern_details table and filtered based on root_form. Maybe the best would be to lay out pattern_details with fields for pattern_id, root_length, root_form, and pattern. Then you just join from the word table through the pattern table to the pattern detail that matches all the right criteria.
Of course, maybe I've completely misunderstood what you're looking for. If so, it would be clearer if you posted some example data and an example result.

Searching for and matching elements across arrays

I have two tables.
In one table there are two columns, one has the ID and the other the abstracts of a document about 300-500 words long. There are about 500 rows.
The other table has only one column and >18000 rows. Each cell of that column contains a distinct acronym such as NGF, EPO, TPO etc.
I am interested in a script that will scan each abstract of the table 1 and identify one or more of the acronyms present in it, which are also present in table 2.
Finally the program will create a separate table where the first column contains the content of the first column of the table 1 (i.e. ID) and the acronyms found in the document associated with that ID.
Can some one with expertise in Python, Perl or any other scripting language help?
It seems to me that you are trying to join the two tables where the acronym appears in the abstract. ie (pseudo SQL):
SELECT acronym.id, document.id
FROM acronym, document
WHERE acronym.value IN explode(documents.abstract)
Given the desired semantics you can use the most straight forward approach:
acronyms = ['ABC', ...]
documents = [(0, "Document zeros discusses the value of ABC in the context of..."), ...]
joins = []
for id, abstract in documents:
for word in abstract.split():
try:
index = acronyms.index(word)
joins.append((id, index))
except ValueError:
pass # word not an acronym
This is a straightforward implementation; however, it has n cubed running time as acronyms.index performs a linear search (of our largest array, no less). We can improve the algorithm by first building a hash index of the acronyms:
acronyms = ['ABC', ...]
documents = [(0, "Document zeros discusses the value of ABC in the context of..."), ...]
index = dict((acronym, idx) for idx, acronym in enumberate(acronyms))
joins = []
for id, abstract in documents:
for word in abstract.split():
try
joins.append((id, index[word]))
except KeyError:
pass # word not an acronym
Of course, you might want to consider using an actual database. That way you won't have to implement your joins by hand.
Thanks a lot for the quick response.
I assume the pseudo SQL solution is for MYSQL etc. However it did not work in Microsoft ACCESS.
the second and the third are for Python I assume. Can I feed acronym and document as input files?
babru
It didn't work in Access because tables are accessed differently (e.g. acronym.[id])

Resources