I learn full text search in postgresql and I need to make english dictionary with FTS. I made dictionary mydict_en. I calculate words with my dictionary and other case with simple dictionary.
CREATE TEXT SEARCH DICTIONARY mydict_en (
TEMPLATE = ispell,
DictFile = english,
AffFile = english,
StopWords = english
);
CREATE TEXT SEARCH CONFIGURATION public.mydict_en (PARSER = default);
ALTER TEXT SEARCH CONFIGURATION mydict_en ADD MAPPING
FOR email, url, url_path, host, file, version,
sfloat, float, int, uint,
numword, hword_numpart, numhword
WITH simple;
ALTER TEXT SEARCH CONFIGURATION mydict_en ADD MAPPING
FOR word, hword_part, hword
WITH mydict_en;
My test table (I add FTS field):
CREATE TABLE matches
(
id Serial NOT NULL,
opponents Varchar(1024) NOT NULL,
metaKeywords Varchar(2048),
metaDescription Varchar(1024),
score Varchar(100) NOT NULL,
primary key (id)
);
ALTER TABLE matches ADD COLUMN fts tsvector;
When I insert data to this table, for example:
INSERT INTO matches (opponents, metaKeywords, metaDescription, score)
VALUES ('heat - thunder', 'nba, ball', 'Heat plays at home.', '99 - 85');
I update my fts field based on priority:
UPDATE matches SET fts =
setweight( coalesce( to_tsvector('mydict_en', opponents),''),'A') ||
setweight( coalesce( to_tsvector('mydict_en', metaKeywords),''),'B') ||
setweight( coalesce( to_tsvector('mydict_en', metaDescription),''),'C') ||
setweight( coalesce( to_tsvector('mydict_en', score),''),'D');
And my fts contain this record:
'85':2 '99':1
Why it contain only numbers, where are words?
Related
I have two tables, one for reviews and another with urls for photos. I want to add the urls to an array in the reviews table. I want to match them based on the id for reviews they both have. Ideally I would be able to add the photos as a JSON object to the array, with one property for the photo id and another for the url. I'm new to postgres and SQL and struggling to come up with the query to be able to do this. Below is the sql for the two tables, below them is my attempt at a query:
CREATE TABLE IF NOT EXISTS public.reviews
(
id integer NOT NULL,
product_id integer NOT NULL,
rating integer,
date text COLLATE pg_catalog."default",
summary text COLLATE pg_catalog."default" NOT NULL,
body text COLLATE pg_catalog."default" NOT NULL,
recommend boolean,
reported boolean,
reviewer_name text COLLATE pg_catalog."default" NOT NULL,
reviewer_email text COLLATE pg_catalog."default" NOT NULL,
response text COLLATE pg_catalog."default",
helpfulness integer,
photos text[] COLLATE pg_catalog."default",
CONSTRAINT reviews_pkey PRIMARY KEY (id)
)
CREATE TABLE IF NOT EXISTS public.photos
(
id integer,
review_id integer,
url text COLLATE pg_catalog."default"
)
update reviews
set photos = array_append(photos, photos.url)
where photos.review_id = reviews.id;
You are missing a FROM clause for the photos table:
update reviews
set photos = array_append(reviews.photos, photos.url)
from photos
where photos.review_id = reviews.id;
Prefixing the photos column on the right hand side of the assignment isn't strictly necessary, but if there is a table and a column with the same name, I find this to be more readable.
Note that array_append(reviews.photos, photos.url) can also be written as reviews.photos || photos.url
Here I am creating table product_feature_text, having a 1:N relation with table product. As the application must support several user languages, a lang_code column is added to segment english texts from other language texts.
As I want to present the product features alphabetically ordered in every language, I have created four partial indexes with their specific collate. It is expected that all products features have title in all of the four languages, i.e., there will be 25% of rows with lang_code = 'ES', for example.
This is an oversimplification of the real case but enough to depict the situation.
create table product_feature_text (
id bigint generated by default as identity primary key,
-- reference to the parent product
product_id bigint not null,
-- language dependent columns
lang_code char(2),
title varchar,
foreign key (product_id) references product (id)
);
create index on product_feature_text (title collate "en-US") where lang_code = 'EN';
create index on product_feature_text (title collate "es-ES") where lang_code = 'ES';
create index on product_feature_text (title collate "fr_FR") where lang_code = 'FR';
create index on product_feature_text (title collate "de_DE") where lang_code = 'DE';
Is this the best index approach for the case?
Addendum from a comment: a typical query would be
select text
from product_feature
where product_id = 1024
and lang_code = 'FR'
order by title collate "fr_FR"
where product_id could be anything.
It depends on the intended use of the indexes.
If you want to use them for
SELECT ... FROM product_feature_text
WHERE lang_code = 'EN' AND ...
ORDER BY title COLLATE "en-US";
your indexes might be useful.
Also, if your query looks like
WHERE product_feature_text > 'bhd' COLLATE ...
it might help.
However, for most cases that I can envision, a single index whose collation doesn't matter would be better.
For the query in the addendum, the perfect index would be:
CREATE INDEX ON product_feature (product_id, title COLLATE "fr_FR")
WHERE lang_code = FR';
I want to import csv with Postgres' arrays into a Postgres table.
This is my table:
create table dbo.countries (
id char(2) primary key,
name text not null,
elements text[]
CONSTRAINT const_dbo_countries_unique1 unique (id),
CONSTRAINT const_dbo_countries_unique2 unique (name)
);
and I want to insert into that a csv which looks like this:
AC,ac,{xx yy}
When I type copy dbo.mytable FROM '/home/file.csv' delimiter ',' csv; then the array is read as a one string: {"xx yy"}.
How to change a deafault separator for arrays from , to ?
You cannot to change array's separator symbol. You can read data to table, and later you can run a update on this table:
UPDATE dbo.countries
SET elements = string_to_array(elements[1], ' ')
WHERE strpos(elements[1], ' ') > 0;
I have a table created like
CREATE TABLE data
(value1 smallint references labels,
value2 smallint references labels,
value3 smallint references labels,
otherdata varchar(32)
);
and a second 'label holding' table created like
CREATE TABLE labels (id serial primary key, name varchar(32));
The rationale behind it is that value1-3 are a very limited set of strings (6 options) and it seems inefficient to enter them directly in the data table as varchar types. On the other hand these do occasionally change, which makes enum types unsuitable.
My question is, how can I execute a single query such that instead of the label IDs I get the relevant labels?
I looked at creating a function for it and stumbled at the point where I needed to pass the label holding table name to the function (there are several such (label holding) tables across the schema). Do I need to create a function per label table to avoid that?
create or replace function translate
(ref_id smallint,reference_table regclass) returns varchar(128) as
$$
begin
select name from reference_table where id = ref_id;
return name;
end;
$$
language plpgsql;
And then do
select
translate(value1, labels) as foo,
translate(value2, labels) as bar
from data;
This however errors out with
ERROR: relation "reference_table" does not exist
All suggestions welcome - at this point a can still alter just about anything...
CREATE TABLE labels
( id smallserial primary key
, name varchar(32) UNIQUE -- <<-- might want this, too
);
CREATE TABLE data
( value1 smallint NOT NULL REFERENCES labels(id) -- <<-- here
, value2 smallint NOT NULL REFERENCES labels(id)
, value3 smallint NOT NULL REFERENCES labels(id)
, otherdata varchar(32)
, PRIMARY KEY (value1,value2,value3) -- <<-- added primary key here
);
-- No need for a function here.
-- For small sizes of the `labels` table, the query below will always
-- result in hash-joins to perform the lookups.
SELECT l1.name AS name1, l2.name AS name2, l3.name AS name3
, d.otherdata AS the_data
FROM data d
JOIN labels l1 ON l1.id = d.value1
JOIN labels l2 ON l2.id = d.value2
JOIN labels l3 ON l3.id = d.value3
;
Note: labels.id -> labels.name is a functional dependency (id is the primary key), but that doesn't mean that you need a function. The query just acts like a function.
You can pass the label table name as string, construct a query as string and execute it:
sql = `select name from ` || reference_table_name || `where id = ` || ref_id;
EXECUTE sql INTO name;
RETURN name;
I have a database about weather that updates every second.
It contains temperature and wind speed.
This is my database:
CREATE TABLE `new_table`.`test` (
`id` INT(10) NOT NULL,
`date` DATETIME() NOT NULL,
`temperature` VARCHAR(25) NOT NULL,
`wind_speed` INT(10) NOT NULL,
`humidity` FLOAT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
I need to find the average temperature every hour.
This is my code:
Select SELECT AVG( temperature ), date
FROM new_table
GROUP BY HOUR ( date )
My coding is working but the problem is that I want to move the value and date of the average to another table.
This is the table:
CREATE TABLE `new_table.`table1` (
`idsea_state` INT(10) NOT NULL,
`dateavg` DATETIME() NOT NULL,
`avg_temperature` VARCHAR(25) NOT NULL,
PRIMARY KEY (`idsea_state`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
Is it possible? Can you give me the coding?
In order to insert new rows into a database based on data you have obtained from another table, you can do this by setting up an INSERT query targeting the destination table, then run a sub-query which will pull the data from the source table and then the result set returned from the sub-query will be used to provide the VALUES used for the INSERT command
Here is the basic structure, note that the VALUES keyword is not used:
INSERT INTO `table1`
(`dateavg`, `avg_temperature`)
SELECT `date` , avg(`temperature`)
FROM `test`;
Its also important to note that the position of the columns returned by result set will be sequentially matched to its respective position in the INSERT fields of the outer query
e.g. if you had a query
INSERT INTO table1 (`foo`, `bar`, `baz`)
SELECT (`a`, `y`, `g`) FROM table2
a would be inserted into foo
y would go into bar
g would go into baz
due to their respective positions
I have made a working demo - http://www.sqlfiddle.com/#!9/ff740/4
I made the below changes to simplify the example and just demonstrate the concept involved.
Here is the DDL changes I made to your original code
CREATE TABLE `test` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`date` DATETIME NOT NULL,
`temperature` FLOAT NOT NULL,
`wind_speed` INT(10),
`humidity` FLOAT ,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
CREATE TABLE `table1` (
`idsea_state` INT(10) NOT NULL AUTO_INCREMENT,
`dateavg` VARCHAR(55),
`avg_temperature` VARCHAR(25),
PRIMARY KEY (`idsea_state`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
INSERT INTO `test`
(`date`, `temperature`) VALUES
('2013-05-03', 7.5),
('2013-06-12', 17.5),
('2013-10-12', 37.5);
INSERT INTO `table1`
(`dateavg`, `avg_temperature`)
SELECT `date` , avg(`temperature`)
FROM `test`;