I have a customer table, which has a field "categories". It's a string holding IDs divided by commas like 1,11,14,21.
Let's say I want to query all customers which have categoryID 1 - what's the proper way to query it?
The problem is that ID 1 could be at the beginning, middle or the end of the string, or even be the only ID so I'd have to cover all cases like:
WHERE categories LIKE '1'
OR categories LIKE '1%,'
OR categories LIKE '%,1,%'
OR categories like '%,1'
Is there a more elegant (and probably much faster) way to do this?
You should instead have a CustomerCategories table which has CustomerID, CategoryID columns, and then have one entry per customers category. This is far easier to query - and is very extremely highly the norm for relational databases.
Storing arrays of IDs in strings is non-relational and as you've found is a nightmare to query.
You should strangle the person who designed the DB to work like that. Never can I think of an instance where you should have delimited data in a field.
On that note, I think this will be a suitable workaround for you.
WHERE ','+[categories]+',' LIKE '%,1,%'
Related
I have the following tables:
In table 2 (yellow looking fields), the first field is part of the following:
name1 RECORD NULLABLE
name1. name2 RECORD REPEATED
name1.name2. date_inserted TIMESTAMP NULLABLE
As you can see the last (sub-row?) of the row 25 is greyed because it is part of the repeated record name1.name2
I am trying to join table 2, with table 1(orange looking fields) on another field. I have 0 experience with records or repeated records but using FLATTEN() I managed to join them.
The problem is, I noticed that some dates from the 2nd after the join return NULL although there aren't any NULLS before it. So since I can't figure out what the greyed cells are I guess I am doing something wrong.
All this sums up to: How can I totally flatten all tables that I want to use so that there won't be any records at all and so I can go through the data with simple SQL statements? Please provide an example as well. Looking for something generic.
How can I totally flatten all tables that I want to use so that there won't be any records at all and so I can go through the data with simple SQL statements?
It really depends on the schemas you are working with. You can preprocess them, flatten the arrays and rename the structs fields, then use that as your base table to work with simple SQL statements
For your scenario, you can start by flattening the table 2, name2 column like this
SELECT
name2.date_inserted -- Add additional fields you want on the result
FROM table2, table2.name1.name2
You can do CROSS JOIN and LEFT JOIN to further adjust your results.
Please provide an example as well. Looking for something generic.
I'm not sure about a generic approach, since each schema would probably have distinct requirements. The key concept is to know how to flatten arrays and how to query struct with arrays and arrays of structs
You can find plenty examples in that documentation
I want to select id in the database table where allot field have a specific integer value in the string.
example:- In the allot column I want to search value 26 in Comma(,) separated string, here result should be id=72
Fix your data structure! You should be using a junction/association table with one row per value and per id. That is the SQL way to represent the data. Why is your structure bad?
Data should be stored using the appropriate type. Numbers should be stored as numbers, not strings.
Columns should contain one value.
Databases have great data structures for storing lists of values. The best known one is tables. Strings are not the appropriate data structures.
SQL engines have (relatively) poor string processing capabilities.
Operations on strings do not (in almost all cases) take advantage of indexes and other engine optimizations.
If these are ids, then foreign key relationships should be properly declared.
Sometimes, we are stuck with other people's really, really bad design decisions. In those cases, you can use like:
SELECT p.id
FROM Prospects p
WHERE ',' || allot || ',' like '%,26,%';
try the commend 'SELECT id FROM (table_name) WHERE allot LIKE '%,26,%'
the '%x%' will look for anything with an x in it in the provided column
basically if you find something with x give it to me
Using the LIKE operator you should be able to solve your requirement. Considering that your table name is Prospects:
SELECT id FROM Prospects
WHERE allot LIKE '%,26,%'
EDIT-1: You can narrow down the search finer by adding additional commas in the query as mentioned here!
EDIT-2: To additionally handle scenarios, you can have the same query with a UNION like this. This is not something that you should be looking to implement, but implement a stored procedure to check these scenarios and handle it in your logic.
SELECT id FROM Prospects
WHERE allot LIKE '%,26,%'
UNION
SELECT id FROM Prospects
WHERE allot LIKE '%,26%'
UNION
SELECT id FROM Prospects
WHERE allot LIKE '%26,%'
Hope this answers your question!
I'm having a table with an id and a name.
I'm getting a list of id's and i need their names.
In my knowledge i have two options.
Create a forloop in my code which executes:
SELECT name from table where id=x
where x is always a number.
or I'm write a single query like this:
SELECT name from table where id=1 OR id=2 OR id=3
The list of id's and names is enormous so i think you wouldn't want that.
The problem of id's is the id is not always a number but a random generated id containting numbers and characters. So talking about ranges is not a solution.
I'm asking this in a performance point of view.
What's a nice solution for this problem?
SQLite has limits on the size of a query, so if there is no known upper limit on the number of IDs, you cannot use a single query.
When you are reading multiple rows (note: IN (1, 2, 3) is easier than many ORs), you don't know to which ID a name belongs unless you also SELECT that, or sort the results by the ID.
There should be no noticeable difference in performance; SQLite is an embedded database without client/server communication overhead, and the query does not need to be parsed again if you use a prepared statement.
A "nice" solution is using the INoperator:
SELECT name from table where id in (1,2,3)
Also, the IN operator is syntactic sugar built for exactly this purpose..
SELECT name from table where id IN (1,2,3,4,5,6.....)
Hoping that you are getting the list of ID's on which you have to perform a query for names as input temp table #InputIDTable,
SELECT name from table WHERE ID IN (SELECT id from #InputIDTable)
I have to do certain actions based on the decision if a sub string exists in a column.
For example my column 'LangCodes' have # separated values like en-us#ar-ae#in-id.
I can use the SQL in operator if I can convert the value in form like : 'en-us','ar-ae','in-id'.
For example select Col1 from Table1 where 'en-us' in (LangCodes)
Do I need to use replace function of SQL to accomplish this or any better way exists?
You cannot do this efficiently in SQL Server, because you are storing your data in a fashion not consistent with the use of relational databases. You need a separate correlation table that has columns id and LangCode, with one row per language code.
You can do what you want with string operations. Here is a typical way:
where '#'+LangCodes+'#' like '%#en-us#%'
This, however, cannot take advantage of an index on LangCodes.
The most efficient and best way to check your languages codes is to seperate them in your table.
Never, never, never store multiple values in one column!
This is how your tables could look like (just examples)
product table
-------------
id
name
language_code table
-------------------
id
name
product_language_code table
---------------------------
product_id
language_code_id
So I am a first time user here, and still relatively new to SQL. I am attempting to take 2 tables, and join them in a sense.
In Table1 I have the data:
House_Key ---Other Fields--- Customer_ID
House_Key is not unique, and as such I can have multiple Customer_IDs per household. House_Key is a numerical code, and Customer_ID is either Home, Business, or Bulk.
In Table2 I have the House_Key field, but not the Customer_ID field.
My goal is to have a new table that holds the fields of Table2 with a field called Customer_ID, but instead of having a new row for each type of Customer_ID like in Table 1, I want to have each House_Key only have one row, and the Customer_ID say something like "Home Business Bulk" if it is all three or any combination of them, but would prefer that it always have Home before Business before Bulk in the field.
Is there any way to do this? Thank you very much ahead of time.
Also, not sure if it matters, but in case it does I'm using SQL Server 2005.
Wow, I'm glad that you came here for an answer, but seems that you really need some reading about relational databases.
Instead of writing looong answer here're the links:
http://en.wikipedia.org/wiki/Database_normalization
http://en.wikipedia.org/wiki/Join_(SQL)