SQL select like - containing only 1 word - sql

A SQL Table has a field with the name:
image_colors
The value of this field can be a row of different colors - example:
green red blue white
When I search for a specific color, I use:
SELECT *
FROM `gallery_images`
WHERE `image_colors` LIKE '%green%'
In this case, the value:
green red blue white
contains green and will be selected.
Question:
Is it possible with SQL to find only values with only 1 Word:
green

Yes, use simple equality comparison to select only values matching green:
select *
from gallery_images
where image_colors = 'green'
Notes:
backticks are not necessary in your case and should be avoided when not needed
you should probably change your data model for many-to-many with colors dictionary table and junction table between gallery_images and colors to normalize your data and make lookups faster

Try to use
SELECT *
FROM gallery_images
WHERE trim(image_colors)= 'green'

Your existing query will work for single word also. No need to do any change for single word value in search field.
But of course this query will degrade performance of your application.
Instead of storing multiple values in single column, it is better to create another table to store colors in form of Integer value as multiple rows.

Do not use Like operator when you want records with only 'green' color.
select *
from gallery_images
where image_colors = 'green'

Related

Return which element matched each row in SQL result

I am programmatically writing SQL queries from user input. I want to show the user for each row returned, which part of their supplied query information matched against that row.
For instance user supplied information looks like:
red:[11,202]
blue:[36]
green:[202]
yellow:[11,36]
This information would build the following query:
SELECT name, list FROM test WHERE list SIMILAR TO '%(11|202|36)%'
But I would like to add a result field similar to the "Matched Element shown below:
name
list
Matched Element
foobar
15,11,19,20
red, yellow
hello
17,30,36,20
blue, yellow
bar
101,202,330,460
red, green
test
15,36,23
blue
I cannot add attempted examples as I do not know the proper language by which to seach for information. My current solution so far is to process the data row by row after the query has returned the result to my script to add the new column, but I would like to know if its possible to achieve this using postgres.
Here is a db-fiddle: https://www.db-fiddle.com/f/nMMB3wVFRTGeZgobmA4F6k/1
I am running postgresql 12.3 however I am able to change version if needed.
I agree with Hambone that you should take advantage of arrays. If you don't want to create an additional table, you could also do it all in one query:
select name, list,
array_to_string(ARRAY[
CASE WHEN list LIKE ANY(ARRAY['%11%', '%202%']) then 'red' else null end,
CASE WHEN list LIKE ANY(ARRAY['%36%']) then 'blue' else null end,
CASE WHEN list LIKE ANY(ARRAY['%202']) then 'green' else null end,
CASE WHEN list LIKE ANY(ARRAY['%11%', '%36%']) then 'yellow' else null end
], ', ')
from test
where list LIKE ANY(ARRAY['%11%', '%202%', '%36%', '%202%', '%11%', '%36%']);
Note that I'm using LIKE ANY instead of SIMILAR TO. You could continue to use SIMILAR TO, but it seems easier to me to use LIKE ANY.
Here's a fiddle.
It sounds like you really need to take advantage of PostgreSQL's most excellent array support. I feel like I say that a lot.
If you change your structure to arrays:
create table test2 (
name varchar(255),
list integer[]
)
Then, notionally you can even put your input into another table:
create table matches (
color text,
list integer[]
);
insert into matches values
('red', '{11,202}'),
('blue', '{36}'),
('green', '{202}'),
('yellow', '{11,36}');
The following query should yield the results you seek:
select
t.name, t.list, array_agg (m.color)
from
test2 t
join matches m on
m.list && t.list
group by
t.name, t.list

How can I replace a column with another column in a different table in sql?

I have two different tables. One of them has text data and the other one has words and their stem. I want to look at all words in the text data and compare these with the second table of words and stems. If there is a connection between table TEXT_DATA and second table DICTIONARY, I want to change it to stem version.
I simply write a code but didn't work.
text data
TEXT
I have chocolates
DICTIONARY
WORD_FORM STEM
chocalates chocolate
SELECT
REPLACE(TEXT,(SELECT WORD_FORM FROM DICTIONARY),(SELECT STEM FROM DICTIONARY))
FROM TEXT_DATA
I want to see my new text like : I have chocolate
Thanks in advance
Consider joining tables with INSTR():
SELECT
REPLACE(t.TEXT, d.WORD_FORM, d.STEM) AS NEW_TEXT
FROM TEXT_DATA t
INNER JOIN DICTIONARY d
ON INSTR(t.TEXT, d.WORD_FORM, 1, 1) > 0

Grab Random Record and Mark As Being Used

Alright, so I have a table called Colors, within that table I have 5 records (Red, Blue, Green, Yellow and Orange). The color table currently has two fields (ID and Color Name). My overall goal is to randomly select a color and mark this color as being used. Rinse and repeat until all colors are used and them mark all colors as being unused.
Here is the SQL on the RandomColorsQuery:
SELECT TOP 1 Colors.[Color Name]
FROM Colors
ORDER BY Rnd(ColorID);
So far, I've been able to select a random color by using the following within VBA and works fine:
Dim RanColor As DAO.Recordset
Set RanColor = CurrentDb.OpenRecordset("RandomColorsQuery")
'MsgBox (RanColor.Fields(0))
Text1.SetFocus
Text1.Text = RanColor.Fields(0)
Obviously I would need to add a new field to the Colors table, say a field called "Used". I'd rather not use a Yes/No field and just add an "X" in the "Used" field when the color is used.
Any suggestions or similar examples on how to accomplish this?
Add a boolean (Yes/No) field.
Modify query to return only those that haven't been used:
SELECT TOP 1 Colors.[Color Name]
FROM Colors
WHERE USED=False
ORDER BY Rnd(ColorID);
In VBA, if the recordset returns a record, grab your color value, and set Used field to True.
If recordset returns doesn't return a record, ie rs.EOF=True, then update Used field in all records to false, and rerun the query to start over.

In PostgresSQL when is it best to use WHERE and when is it best to use CASE WHEN?

I don't really understand the difference between CASE WHEN and WHERE, can they be used to achieve the same thing? Will someone please clarify?
Thanks!
To understand the difference between the two, you have to think of the classic structure of a SQL statement:
SELECT ...
FROM ...
WHERE ...
ORDER BY ...;
For example, if you think of a table called "shirts" with 500 rows, let's start by selecting all 500 of them:
-- first example: all rows as stored
SELECT
name,
color,
size,
maker
FROM shirts
ORDER BY name;
Next, let's add a WHERE clause. This serves to limit the rows returned in the final result set to only those that match some specified criterion. For instance, you can say "WHERE color = 'white'" to return a smaller set of (say) 80 rows:
-- second example: only some rows
SELECT
name,
color,
size,
maker
FROM shirts
WHERE color = 'white'
ORDER BY name;
The CASE statement serves an entirely different function: it is normally part of the SELECT clause-- it cannot be a separate clause in its own right-- and serves to reformat the output you receive in some way. So with a case statement, you would still get all 500 rows back, but your results won't look the same as they did in my first example:
-- third example: all rows, but color field is tweaked
SELECT
name,
(CASE WHEN color = 'white' THEN 'white' ELSE 'other' END) AS tweaked_color,
size,
maker
FROM shirts
ORDER BY name;
In my first example, you'd have seen various values for "color": "white", "black", "brown", "yellow", "red", etc. With this third example, you'll see 80 rows with "white" and 420 rows with "other".
Hope that helps clarify the difference.
P.S. please note that I've arranged the whitespace in my examples in a somewhat unusual way for clarity's sake; how your arrange the whitespace doesn't make any difference to the syntax. I also added a pair of unnecessary parentheses around the CASE statement to help add some visual clarity; those also would usually be omitted.

Nested loop to match colors

Basically I have a table of colors, now I implemented a query which matches all colors together. I was wondering is it possible to do this with a loop? (perhaps it is a nested loop).
My idea is to loop the first color with every other color and then loop the second color with every other etc. Help is greatly appreciated.
My table - contains different colors
CREATE TABLE Colors
(c_ID VARCHAR2(3) NOT NULL,
c_NAME VARCHAR2(11));
INSERT INTO Colors VALUES
('T01','RED');
INSERT INTO Colors VALUES
('T02','BLUE');
INSERT INTO Colors VALUES
('T03','BLACK');
INSERT INTO Colors VALUES
('T04','YELLOW');
INSERT INTO Colors VALUES
('T05','ORANGE');
The sql query that I used to match different colors:
select a.c_id as HM, s.c_id as AW
from colors a, colors s
where a.c_id <> s.c_id
order by a.c_id;
Recursive query. (this is for Postgres, Your Syntax May Vary)
CREATE TABLE Colors
(c_ID INTEGER NOT NULL
, c_NAME VARCHAR
);
INSERT INTO Colors VALUES
(1,'RED'), (2,'BLUE'), (3,'BLACK'), (4,'YELLOW'), (5,'ORANGE');
WITH RECURSIVE xxx AS (
SELECT
c1.c_ID AS last_id
, c1.c_NAME::text AS all_colors
FROM Colors c1
UNION ALL
SELECT c2.c_ID AS last_id
, x.all_colors|| '+' || c2.c_NAME::text AS all_colors
FROM Colors c2
JOIN xxx x ON x.last_id < c2.c_ID
)
SELECT all_colors
FROM xxx
;
Results:
CREATE TABLE
INSERT 0 5
all_colors
------------------------------
RED
BLUE
BLACK
YELLOW
ORANGE
RED+BLUE
RED+BLACK
RED+YELLOW
RED+ORANGE
BLUE+BLACK
BLUE+YELLOW
BLUE+ORANGE
BLACK+YELLOW
BLACK+ORANGE
YELLOW+ORANGE
RED+BLUE+BLACK
RED+BLUE+YELLOW
RED+BLUE+ORANGE
RED+BLACK+YELLOW
RED+BLACK+ORANGE
RED+YELLOW+ORANGE
BLUE+BLACK+YELLOW
BLUE+BLACK+ORANGE
BLUE+YELLOW+ORANGE
BLACK+YELLOW+ORANGE
RED+BLUE+BLACK+YELLOW
RED+BLUE+BLACK+ORANGE
RED+BLUE+YELLOW+ORANGE
RED+BLACK+YELLOW+ORANGE
BLUE+BLACK+YELLOW+ORANGE
RED+BLUE+BLACK+YELLOW+ORANGE
(31 rows)
If I understand you correctly you want all colors in a single row, or even in a single column of a single row?
The query you show, will only result in pairs of colors. If you want all colors, you need to self-join as many times as you have colors. So adding or removing a color will turn your ugly query into a broken query. In general you will have a query result, where the number of columns depends on the number of colors. This does not play well with the relational paradigm.
If you just want all colors as a single value, then you need to aggregeate colors. The query result will then be a single value, with all the colors combined, possibly separated by commas.
To aggregate things you need an aggregate function. Well-known aggregate functions are SUM, MIN or AVG, none of which do what you need here. What aggregate function to chose depends on your particular SQL dialect.
For oracle you may look into pivot or xmlagg.
You may also consider wrapping the whole thing in procedural code.