SQLite3 - How to select a specific number from a string - sql

I have a table named shoes:
Shoe_model price sizes
-----------------------------------------------
Adidas KD $55 '8, 9, 10, 10.5, 11, 11.5'
Nike Tempo $56 '8, 9, 11.5'
Adidas XL $30.99 '9, 10, 11, 13'
How can I select a row for a specific size?
My attempt:
SELECT * FROM shoes WHERE sizes = '10';
Is there a way around this? Using LIKE will get you both 10 and 10.5 sizes so I'm trying to use WHERE for this. Thanks

First, you should not be storing the sizes as a comma delimited string. You should have a separate row with one row per size per show. That is the SQLish way to store things.
Sometimes, we are stuck with other people's really bad design decisions. In you can do something like this:
SELECT *
FROM shoes
WHERE ',' || '10' || ',' LIKE '%,' || sizes || ',%';
The delimiters are important so "10" doesn't match "100".

Related

Big Query -- Reorder elements within a delimited string by another delimiter

Summary
I'd like to reorder elements in a string, the elements are delimited by new lines.
The elements I'd like to sort should be ordered by a string that can have numbers or letters within it. This sorting string is not at the beginning of the data, but rather it is also a delimited string (messy data set, I know). To make this even messier, there is an extra new line; this doesn't seem like the crux of this issue
Example
Below is a simplified version of what I'd like to do. I have a table, and I'd like to sort students' favorite shows and characters by the show's name, which is the second element of a pipe-delimited string.
student
favorite characters and shows
alice
10th doctor | dr who troy | community
bob
11 | stranger things Liz | 30 Rock mr peanut butter | bojack horseman
would become this:
student
favorite characters and shows
alice
troy | community 10th doctor | dr who
bob
Liz | 30 Rock mr peanut butter | bojack horseman 11 | stranger things
What I've tried
Big Query doesn't allow arrays of arrays. If it did, I would have an easier time here. I've tried working with COLLATE but today is my first time seeing that function; I'm not sure that is the right way to go, anyways.
Currently, I'm working to split by new line, and rejoin later. I have never done this with tables, so I'm a bit out of my element. Here is the query I'm working from:
WITH
-- example data from above
example_data AS (
SELECT
'alice' AS student,
-- note: the new line is at the end of every pipe-delimited line, so there is always some floating empty row when using functions like split()
'10th doctor | dr who\ntroy | community\n' AS favorite_characters_and_shows
UNION ALL
SELECT
'bob' AS student,
"11 | stranger things\nLiz | 30 Rock\nmr peanut butter | bojack horseman\n" AS favorite_characters_and_shows ),
-- I have no need for this to be another table, but it is where I am. Tell me if this is misguided, please.
soln_table AS (
SELECT
example_data.student,
example_data.favorite_characters_and_shows,
SPLIT(example_data.favorite_characters_and_shows, '\n'),
array( select x from unnest(SPLIT(example_data.favorite_characters_and_shows, '\n') ) as x order by x) as foo,
FROM
example_data )
-- where I am trying to display a sorted solution
SELECT
*
FROM
soln_table;
Consider below approach
select student, (
select string_agg(line, '\n' order by split(line, '|')[safe_offset(1)])
from unnest(split(favorite_characters_and_shows, '\n')) line
where trim(line) != ''
) as favorite_characters_and_shows
from example_data
if applied to sample data in your question - output is

How to count the number of variants in SQL in the same column

product name
price
model_id
iPhone 11
600
1234576854,48503843246,23486759403,56482049586
iPhone 11pro
600
1234576854,48503843246,23486759403,56482049586,47586940382
Column model_id is showing the number of models in each product for example iPhone 11 has 4 variants while iPhone 11 Pro has 5.
I want to see how many variants for each product and the average of column mode_id.
The output should look something like this:
product name
price
model_id
number of vibrant
iPhone 11
600
1234576854,48503843246,23486759403,56482049586
4
iPhone 11pro
600
1234576854,48503843246,23486759403,56482049586,47586940382
5
You could use a replacement trick here:
SELECT
product_name,
price,
model_id,
LENGTH(model_id) - LENGTH(REPLACE(model_id, ',', '')) + 1 AS "number of vibrant"
FROM yourTable;
But regarding your current table design, in particular the model_id column, it is generally best to avoid storing unnormalized CSV data in your tables. Do some research about database normalization to learn more about good database design.

SQL query find rows that share the same tags

Let's see if someone can help me...
On a product page, I have to show related products. These products are related depending on their tags. For example my product (ID 23) has the following tags: cooking, noodles, healthy.
What I have to do, is a SQL query, that search for products that have the tags "cooking, noodles, healthy" but separately
First search for all the products that have "cooking" in their tags, then look for other products to have "noodles" , and finally "healthy".
The products shown have to be in order: first show all products that have "cooking" in the tags column, then "noodles" and lastly "healthy". Important, the products do not have to be repeated.
This is the order I hope to get: ID: 25, 25, 40, 43, 46
This is the database
ID
Tags
Name
23
cooking, noodles, healthy
Noodles Hot white pepper
25
cooking, noodles, healthy
Soap of noodles
35
cooking, noodles, healthy
Noodles with carrots
40
food, noodles, ketchup
New Noodles with ketchup
43
apple, cook, healthy
Apple with sugar
46
banana, cook, healthy
Banana with sugar
Thanks for the help!!
The way you store your data makes things unnecessarily suboptimal. You should not have multiple strings stored in a single column; instead, there should be another table to store the relation between products and tags, with each tuple should on a separate row.
For your current design, you can do:
select t.*
from mytable t
where
',' || tags || ',' like '%,cooking,%'
or ',' || tags || ',' like '%,noodles,%'
or ',' || tags || ',' like '%,healthy,%'
order by
case
when ',' || tags || ',' like '%,cooking,%' then 1
when ',' || tags || ',' like '%,noddles,%' then 2
else 3
end,
id
This uses standard string concatenation operator ||: you might need to adapt that to your actual database.
Some databases have built-in functions to search a CSV list. If, for example, you are running MySQL:
select t.*
from mytable t
where
find_in_set('cooking', tags)
or find_in_set('noodles', tags)
or find_in_set('healthy', tags)
order by
case
when find_in_set('cooking', tags) then 1
when find_in_set('noodles', tags) then 2
else 3
end,
id

Searching records by first letters of any word in string

Searching records by first letters of any word in string.
I need to search records by multiple probes from single row in sql
e.g.
Table:
AcCode AcTitle
1 Hussain Mills Limited
2 Nishat Chunian Limited
3 Nishat Mills Limited
4 MCB Bank Limited
5 Allied Bank Limited
Required
When searched by string "Ni Lim" should return record 2 and 3
When searched by string "Bank Li" should return record 4 and 5
Hmmm. I think you can do this with replace() and like:
select t.*
from table t
where acTitle like '% ' + replace(#string, ' ', '% ') + '%'

Finding data from specific value in an array in SQL

Morning All,
I have an Allowed systems field in my record that can contain an array such as: 22, 18, 21
What I want to do is if system 18 is accessing the database and is pulling all the records that are allowed for system 18, how can I write that in sql.
+----------+----------------+------------+
| AdvertID | AllowedSystems | AdvertName |
+----------+----------------+------------+
| 47 | 22, 18, 21, 3 | GeorgesAd |
+----------+----------------+------------+
| 49 | 2, 7, 9, 6 | StevesAd |
+----------+----------------+------------+
| 47 | 18, 12, 32, 8 | PetesAd |
+----------+----------------+------------+
Any assistance would be greatly appreciated.
Have a great day..!
Paul Jacobs
This will test for the best performing cases first, in the hopes of getting some performance out of what is destined to be an inefficient query due to the denormalized structure.
The first two WHERE clauses can take advantage of an index on AllowedSystems, although this may be helpful in only a small number of cases, depending on what your data is like.
select AdvertID, AdvertName
from MyTable
where AllowedSystems = '18'
or AllowedSystems like '18,%'
or AllowedSystems like '%, 18'
or AllowedSystems like '%, 18,%'
Note: I add a space to the beginning of the searched column and a comma to the end to account for the cases where 18 is the first or last entry in the list. I then search for ' 18,' within the string.
select *
from YourTable
where charindex(' 18,', ' ' + AllowedSystems + ',') <> 0
First, this is a bad idea for a data structure. You should probably normalize by adding an AllowedSystems table with a record for each pair of system and Advert.
Second, you would want to use this:
SELECT AdvertID, AdvertName
FROM MyTable
WHERE AllowedSystems LIKE '%18%'
You're going to have issues when you get over 100 systems, since there is no way to tell if the hit is for 18 or 118 or 181.
EDIT:
Or you can use RedFilter's multiple WHERE conditions to avoid the above issue with 18, 118, or 181.
The poor performance way would be:
SELECT AdvertID, AdvertName
FROM YourTable
WHERE ', ' + AllowSystems + ', ' LIKE '%, 18, %'
However, ideally you should have an extra table that has a compound key:
Table: AdvertAllowedSystem
AdvertID
SystemID
so that you can do a more performant, SARGable query:
SELECT a.AdvertID, a.AdvertName
FROM AdvertAllowedSystem s
INNER JOIN Advert a ON s.AdvertId = a.AdvertId
WHERE s.SystemId = 18
In addition if you have possibility to changed the design of create a materialized view, for this you may use hierarchyid Data Type or Rank and Unrank