How to implement searching concept using keywords in SQL - sql

Can anyone guide how to implement the keyword search concept in SQL.Is there only “Like” operator available or any other options there?
Example: - Table:
Keyword -- Questions -- Answers
Where,pen -- Where is my pen? -- Pen is on the table
Where ,pen, kept -- where you have kept the pen -- Pen is under the
table
Input - Where is my pen?
Output should be - “Pen is on the table”
In this part I have to split the keyword from input and check the keyword with db to send the output. I should get only one output from above .Because in second row value also have “where,pen” keyword
Could anyone suggest how this logic will be implemented .
I would like to know If any keyword creating option can done in SQL part itself.

You do not want to store the keywords in a comma separated list. Instead, you want a separate table, say QuestionKeywords:
create table QuestionKeywords (
QuestionKeywordsId int identity(1, 1) primary key,
QuestionId int not null references Questions(QuestionId),
Keyword varchar(255),
constraint unq_QuestionKeywords_QuestionId_Keyword unique (QuestionId, Keyword)
);
You can then search for keywords just using equality or in.

Related

Postgres ATOMIC stored procedure INSERT INTO . . . SELECT with one parameter and one set of rows from a table

I am trying to write a stored procedure to let a dev assign new user identities to a specified group when they don't already have one (i.e. insert a parameter and the output of a select statement into a joining table) without hand-writing every pair of foreign keys as values to do so. I know how I'd do it in T-SQL/SQL Server but I'm working with a preexisting/unfamiliar Postgres database. I would strongly prefer to keep my stored procedures as LANGUAGE SQL/BEGIN ATOMIC and this + online examples being simplified and/or using constants has made it difficult for me to get my bearings.
Apologies in advance for length, this is me trying to articulate why I do not believe this question is a duplicate based on what I've been able to find searching on my own but I may have overcorrected.
Schema (abstracted from the most identifying parts; these are not the original table names and I am not in a position to change what anything is called; I am also leaving out indexing for simplicity's sake) is like:
create table IF NOT EXISTS user_identities (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
[more columns not relevant to this query)
)
create table IF NOT EXISTS user_groups (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
name TEXT NOT NULL
)
create table IF NOT EXISTS group_identities (
user_id BIGINT REFERENCES user_identities(id) ON DELETE RESTRICT NOT NULL,
group_id BIGINT REFERENCES user_groups(id) ON DELETE RESTRICT NOT NULL
)
Expected dev behavior:
Add all predetermined identities intended to belong to a group in a single batch
Add identifying information for the new group (it is going to take a lot of convincing to bring the people involved around to using nested stored procedures for this if I ever can)
Bring the joining table up to date accordingly (what I've been asked to streamline).
If this were SQL Server I would do (error handling omitted for time and putting aside whether EXCEPT or NOT IN would be best for now, please)
create OR alter proc add_identities_to_group
#group_name varchar(50) NULL
as BEGIN
declare #use_group_id int
if #group_name is NULL
set #use_group_id = (select Top 1 id from user_groups where id not in (select group_id from group_identities) order by id asc)
ELSE set #use_group_id = (select id from user_groups where name = #group_name)
insert into group_identities (user_id, group_id)
select #use_group_id, id from user_identities
where id not in (select user_id from group_identities)
END
GO
Obviously this is not going to fly in Postgres; part of why I want to stick with atomic stored procedures is staying in "neutral" SQL, both to be closer to my comfort zone and because I don't know what other languages the database is currently set up for, but my existing education has played kind of fast and loose with differentiating what was T-SQL specific at any point.
I am aware that this is not going to run for a wide variety of reasons because I'm still trying to internalize the syntax, but the bad/conceptual draft I have written so that I have anything to stare at is:
create OR replace procedure add_identities_to_groups(
group_name text default NULL ) language SQL
BEGIN ATOMIC
declare use_group_id integer
if group_name is NULL
set use_group_id = (select Top 1 id from user_groups
where id not in (select user_id from group_identities)
order by id asc)
ELSE set use_group_id = (select id from user_groups where name = group_name) ;
insert into group_identities (group_id, user_id)
select use_group_id, id from user_identities
where id not in (select user_id from group_identities)
END ;
GO ;
Issues:
Have not found either answers for how to do this with the combination of a single variable and a column with BEGIN ATOMIC or hard confirmation that it wouldn't work (e.g. can atomic stored procedures just not accept parameters? I cannot find an answer to this on my own). (This is part of why existing answers that I can find here and elsewhere haven't been clarifying for me.)
~~Don't know how to compensate for Postgres's not differentiating variables and parameters from column names at all. (This is why examples using a hardcoded constant haven't helped, and they make up virtually all of what I can find off StackOverflow itself.)~~ Not a problem if Postgres will handle that intelligently within the atomic block but that's one of the things I hadn't been able to confirm on my own.
Google results for "vanilla" SQL unpredictably saturated with SQL Server anyway, while my lack of familiarity with Postgres is not doing me any favors but I don't know anyone personally who has more experience than I do.
because I don't know what other languages the database is currently set up for
All supported Postgres versions always include PL/pgSQL.
If you want to use procedural elements like variables or conditional statements like IF you need PL/pgSQL. So your procedure has to be defined with language plpgsql - that removes the possibility to use the ANSI standard BEGIN ATOMIC syntax.
Don't know how to compensate for Postgres's not differentiating variables and parameters from column names at all.
You don't. Most people simply using naming conventions to do that. In my environment we use p_ for parameters and l_ for "local" variables. Use whatever you prefer.
Quote from the manual
By default, PL/pgSQL will report an error if a name in an SQL statement could refer to either a variable or a table column. You can fix such a problem by renaming the variable or column, or by qualifying the ambiguous reference, or by telling PL/pgSQL which interpretation to prefer.
The simplest solution is to rename the variable or column. A common coding rule is to use a different naming convention for PL/pgSQL variables than you use for column names. For example, if you consistently name function variables v_something while none of your column names start with v_, no conflicts will occur.
As documented in the manual the body for a procedure written in PL/pgSQL (or any other language that is not SQL) must be provided as a string. This is typically done using dollar quoting to make writing the source easier.
As documented in the manual, if you want to store the result of a single row query in a variable, use select ... into from ....
As documented in the manual an IF statement needs a THEN
As documented in the manual there is no TOP clause in Postgres (or standard SQL). Use limit or the standard compliant fetch first 1 rows only instead.
To avoid a clash between names of variables and column names, most people use some kind of prefix for parameters and variables. This also helps to identify them in the code.
In Postgres it's usually faster to use NOT EXISTS instead of NOT IN.
In Postgres statements are terminated with ;. GO isn't a SQL command in SQL Server either - it's a client side thing supported by SSMS. To my knowledge, there is no SQL tool that works with Postgres that supports the GO "batch terminator" the same way SSMS does.
So a direct translation of your T-SQL code to PL/pgSQL could look like this:
create or replace procedure add_identities_to_groups(p_group_name text default NULL)
language plpgsql
as
$$ --<< start of PL/pgSQL code
declare --<< start a block for all variables
l_use_group_id integer;
begin --<< start the actual code
if p_group_name is NULL THEN --<< then required
select id
into l_use_group_id
from user_groups ug
where not exists (select * from group_identities gi where gi.id = ug.user_id)
order by ug.id asc
limit 1;
ELSE
select id
into l_use_group_id
from user_groups
where name = p_group_name;
end if;
insert into group_identities (group_id, user_id)
select l_use_group_id, id
from user_identities ui
where not exists (select * from group_identities gi where gi.user_id = ui.id);
END;
$$
;

Oracle SQL Developer Postal Code

I am having a problem with a check constraint in Oracle SQL Developer with Oracle 11g Express Edition.
I want to check if my postal code which is stored as CHAR just contains numbers and no other signs.
Tried various possibilities but nothing worked...
PLZ VARCHAR(5) NOT NULL
ADD CONSTRAINT TC_PLZ CHECK (PLZ LIKE '[0-9][0-9][0-9][0-9][0-9]')
Thanks and best regards,
Michael
Use regexp_like():
ADD CONSTRAINT TC_PLZ CHECK ( regexp_like(PLZ, '^[0-9]{5}$') )
Oracle -- like most databases -- only supports the ANSI standard wildcards in LIKE. These are % for zero or more characters and _ for exactly one character.
Regular expressions are much more powerful (although generally slower).
This might be a bit more efficient:
ADD CONSTRAINT TC_PLZ CHECK (translate(PLZ, '0123456789', '000000000') = '00000')
although I would go with the regular expression for clarity.
If you want to use regular expression patterns you need to use a regex function in the CHECK constraint. This will work:
create table t23 (
PLZ VARCHAR(5) NOT NULL
, CONSTRAINT TC_PLZ CHECK (regexp_LIKE(plz, '^[0-9]{5}$'))
);
Although there's no need for regex; here's an alternative implementation:
create table t42 (
PLZ NUMBER(5,0) NOT NULL
, CONSTRAINT T42_PLZ CHECK (length(plz)=5)
);
It's good practice to store numeric values using the correct datatype.
Check out this LiveSQL demo.
As #MT0 points out, the numeric implementation is not correct if a valid value can start with a leading zero. My purist data modeller persona states that values which must be a fixed number of digits should start at 10000 (for five digit values). However, I must admit I know of one system that did permit leading zeroes in a "numeric" field; they compounded this by allowing variable level values, which meant code 0300 identified something different from 00300. What larks!

How to use sql def variable

I'm trying to declare a variable in a simple sql script to create some tables in a schema, but it's not working.
Here's a snippet of my sql script:
DEF SCHEMA_NAME = MY_SCHEMA;
CREATE TABLE &SCHEMA_NAME.BOOK
(
BOOK_ID INTEGER
);
That's creating a table with the table name MY_SCHEMABOOK instead of a table named BOOK in the schema MY_SCHEMA.
The script output in Oracle Sql Developer says:
old:CREATE TABLE &SCHEMA_NAME.BOOK
(
BOOK_ID INTEGER
)
new:CREATE TABLE MY_SCHEMABOOK
(
BOOK_ID INTEGER
)
table MY_SCHEMABOOK created.
If that helps. Also, it seems that changing it to &SCHEMA_NAME..BOOK does make it work like I want it to, but having to put two periods doesn't make sense to me. Can anyone tell me what I'm doing wrong?
SET CON[CAT] {. | c | ON | OFF}
Sets the character used to terminate a substitution variable reference
when SQL*Plus would otherwise interpret the next character as a part
of the variable name.
SQL*Plus resets the value of CONCAT to a period when you switch CONCAT on.
http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12040.htm#sthref2722
SQL Developer works the same way - your first period is interpreted as a substitution variable terminator. So, it is perfectly valid to use two consequent periods in this case.

Full-Text Catalog unable to search Primary Key

I have create this little sample Table Person.
The Id is a primary key and is identity = True
Now when I try to create a FullText Catalog, I'm unable to search for the Id.
If I follow this wizard, I'll end up with a Catalog, where its only possible to search for a persons name. I would really like to know, how I can make it possible to do a fulltext search for both the Id and Name.
edit
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, 'anders' );
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, '1' );
I would like them to return the same result, the first returns id = 1 name = Anders, while the second query don't return anything.
edit 2
Looks like the problem is in using int, but is it not possible to trick FullText to support it?
edit 3
Created a view where I convert the int to a nvarchar. CONVERT(nvarchar(50), Id) AS PersonId this did make it possible for me to select that column, when creating the Full Text Catalog, but It still won't let me find it searching for the Id.
From reading your question, I am not sure that you understand the purpose of a full-text index. A full-text index is intended to search TEXT (one or more columns) on a table. And not just as a replacement for:
SELECT *
FROM table
WHERE col1 LIKE 'Bob''s Pizzaria%'
OR col2 LIKE 'Bob''s Pizzaria%'
OR col3 LIKE 'Bob''s Pizzaria%'
It also allows you to search for variations of "Bob's Pizzaria" like "Bobs Pizzeria" (in case someone misspells Pizzeria or forgot to put in the ' or over-zealous anti-SQL-injection code stripped the ') or "Robert's Pizza" or "Bob's Pizzeria" or "Bob's Pizza", etc. It also allows you to search "in the middle" of a text column (char, varchar, nchar, nvarchar, etc.) without the dreaded "%Bob%Pizza%" that eliminates any chance of using a traditional index.
Enough with the lecture, however. To answer your specific question, I would create a separate column (not a "computed column") "IdText varchar(10)" and then an AFTER INSERT trigger something like this:
UPDATE t
SET IdText = CAST(Id AS varchar(10))
FROM table AS t
INNER JOIN inserted i ON i.Id = t.Id
If you don't know what "inserted" is, see this MSDN article or search Stack Overflow for "trigger inserted". Then you can include the IdText column in your full-text index.
Again, from your example I am not sure that a full-text index is what you should use here but then again your actual situation might be something different and you just created this example for the question. Also, full-text indexes are relatively "expensive" so make sure you do a cost-benefit analysis. Here is a Stack Overflow question about full-text index usage.
Why not just do a query like this.
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, '1' )
OR ID = 1
You can leave off the "OR ID = 1" part if by first checking if the search term is a number.

Can we have the table name as "option" in MySQL?

I am very, very new to MYSQL.I tried to create a table named "option".
My SQL Query is :
create table option(
id int not null primary key auto_increment,
choice varchar(30)
)
While executing this query it shows the following error
Error Code : 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'option(
id int not null primary key auto_increment,
choice varchar(30)
)' at line 1
(0 ms taken)
If I try with the table name as "choice" it is working.
can we have the table name as "option" in mysql?
thanks
If you want to have a table name Option, you should be able to, just remember that whenever you use the table in a query, you will have to encase it in ` symbols. Like this.
`option`
The ` key on the top left of your keyboard, with the tilde.
Pick a different name (one that isn't a reserved word in your RDBMS) and save yourself and whoever else might work on it many headaches.
option is a reserved word in Mysql.we can use a reserved word by using the word inside a single quotes.
Better you select the other tablename.Ohterwise maintaining our code will be difficult.
You can use SQL keywords as table names in MySQL if you escape them with back-quotes.
CREATE TABLE `option` (
...
)
It's not normally a good idea to do so, though.
option is a reserved word in MySQL. Save yourself a world of pain and use choice for your table name.
See the MySQL documentation on this. You can do it as follows:
create table `option` (
...
)
Yes you can definitely create a table named option but in every query you will have to use
`option`
instead of plain option. Better improvise a little and create a table named options to save from trouble. Restrain from using mysql reserved words as table name or column name or procedure names.