How to get string fields from sphinx RT index - sphinx

Can't get the title field from the below table,
RT Structure have the below fields,
id, gid, title
But when run below query can't get the title field,
SELECT * FROM rt WHERE MATCH('test');
+------+--------+------+
| id | weight | gid |
+------+--------+------+
| 1 | 1643 | 123 |
| 2 | 1643 | 234 |
+------+--------+------+
How to get the title field from rt index ?
Thanks in advance,

You can't get fields out. Fields are indexed, but they are NOT stored.
You only get attributes. Can make title BOTH a field and an attribute.
rt_field = title
rt_attr_string = title
then can insert into it...
INSERT INTO rt ( id, title ) VALUES ( 3, 'third row' ), ( 4, 'fourth entry' );
Which will use it for both.

Related

Efficient way to conditionally update values in 2 records in PostgreSQL

I have a table that contains 4 columns
id | category | score | enabled
1 | news | 95 | t
id -- serial
category -- varchar
score -- float
enabled -- bool
I want to update enabled to False if there's another record with a higher score.
For example, if I have:
id | category | score | enabled
1 | news | 95 | t
Then, after some operation, a new record with the same category is inserted:
id | category | score | enabled
1 | news | 95 | t
2 | news | 100 | f
Since the score for id=2 is higher, I want to change enabled for id=2 to True and change enabled for id=1 to False.
I'm wondering if I can combine these operations into 1 query. Right now I do 2 SELECT queries to get the 2 records, then compare the scores locally, and then change the enabled value (if needed).
So simply,
SELECT id, score
FROM table
WHERE category = %s
AND enabled = True
SELECT id, score
FROM table
WHERE category = %s
AND id = (SELECT max(id) WHERE category=%s)
if score2>= score1:
UPDATE table SET enabled = True
WHERE id = id2
UPDATE table SET enabled = False
WHERE id = id1
It works, but it seems very inefficient. Any way to improve these queries?
You can do that with a single update:
update the_table
set enabled = (score = t.max_score)
from (
select id, category, max(score) over (partition by category) as max_score
from the_table
where category = 'news'
) t
where t.id = the_table.id
and t.category = the_table.category;
This will set the enabled flags for all rows with the same category in a single statement.
Online example: https://rextester.com/DXR80618
If you happen to have more than one row with the same highest score for one category, the above statement will change enabled to true for all of, .
E.g.
id | category | score
---+----------+------
1 | news | 95
2 | news | 100
3 | news | 100
If you don't want that, and e.g. always pick the one with the lowest id to be the enabled row, you can use the following:
update the_table
set enabled = (rn = 1)
from (
select id, category,
row_number() over (partition by category order by score desc, id) as rn
from the_table
where category = 'news'
) t
where t.id = the_table.id
and t.category = the_table.category;
Online example: https://rextester.com/JPA61125

Fetch records with distinct value of one column while replacing another col's value when multiple records

I have 2 tables that I need to join based on distinct rid while replacing the column value with having different values in multiple rows. Better explained with an example set below.
CREATE TABLE usr (rid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(12) NOT NULL,
email VARCHAR(20) NOT NULL);
CREATE TABLE usr_loc
(rid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
code CHAR NOT NULL PRIMARY KEY,
loc_id INT NOT NULL PRIMARY KEY);
INSERT INTO usr VALUES
(1,'John','john#product'),
(2,'Linda','linda#product'),
(3,'Greg','greg#product'),
(4,'Kate','kate#product'),
(5,'Johny','johny#product'),
(6,'Mary','mary#test');
INSERT INTO usr_loc VALUES
(1,'A',4532),
(1,'I',4538),
(1,'I',4545),
(2,'I',3123),
(3,'A',4512),
(3,'A',4527),
(4,'I',4567),
(4,'A',4565),
(5,'I',4512),
(6,'I',4567);
(6,'I',4569);
Required Result Set
+-----+-------+------+-----------------+
| rid | name | Code | email |
+-----+-------+------+-----------------+
| 1 | John | B | 'john#product' |
| 2 | Linda | I | 'linda#product' |
| 3 | Greg | A | 'greg#product' |
| 4 | Kate | B | 'kate#product' |
| 5 | Johny | I | 'johny#product' |
| 6 | Mary | I | 'mary#test' |
+-----+-------+------+-----------------+
I have tried some queries to join and some to count but lost with the one which exactly satisfies the whole scenario.
The query I came up with is
SELECT distinct(a.rid)as rid, a.name, a.email, 'B' as code
FROM usr
JOIN usr_loc b ON a.rid=b.rid
WHERE a.rid IN (SELECT rid FROM usr_loc GROUP BY rid HAVING COUNT(*) > 1);`
You need to group by the users and count how many occurrences you have in usr_loc. If more than a single one, then replace the code by B. See below:
select
rid,
name,
case when cnt > 1 then 'B' else min_code end as code,
email
from (
select u.rid, u.name, u.email, min(l.code) as min_code, count(*) as cnt
from usr u
join usr_loc l on l.rid = u.rid
group by u.rid, u.name, u.email
) x;
Seems to me that you are using MySQL, rather than IBM DB2. Is that so?

Postrge: rows to columns

i have table which contains street names in several languages:
streetName(addressId uuid, languageCode text, name text);
with values:
addressid |languagecode |name |
-------------------------------------|-------------|----------------|
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |cz |streetName_1_cz |
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |en |streetName_1_en |
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |fi |streetName_1_fi |
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |sv |streetName_1_sv |
bff096cc-4d4d-4b2e-aac2-bdc6ab659a72 |fi |streetName_2_fi |
bff096cc-4d4d-4b2e-aac2-bdc6ab659a72 |cz |streetName_2_cz |
and need to transform street names in cz, fi, en to columns.
(exactly those three languages even if there are more languages in the table, and it can happen, that value for some of those three language is missing).
so expected result is:
addressid |streetNameCz |streetNameEn |streetNameFi |
-------------------------------------|----------------|----------------|----------------|
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |streetName_1_cz |streetName_1_en |streetName_1_fi |
bff096cc-4d4d-4b2e-aac2-bdc6ab659a72 |streetName_2_cz | |streetName_2_fi |
How should do it?
I tried to use crosstable, but it didn't work correctly because there are missing values for some languages,
so i had result like:
addressid |streetNameCz |streetNameEn |streetNameFi |
-------------------------------------|----------------|----------------|----------------|
e5c8c25c-f21e-47df-9172-7f3c7e52d669 |streetName_1_cz |streetName_1_en |streetName_1_fi |
bff096cc-4d4d-4b2e-aac2-bdc6ab659a72 |streetName_2_cz |streetName_2_fi | |
which is not correct :-(.
This is select i used:
SELECT *
FROM crosstab(
'select
"addressid"::uuid as rowid,
languagecode::text as attribute,
name::text as value
from streetName
where languageCode in (''cz'', ''en'', ''fi'')
order by 1, 2')
AS ct(row_name uuid, "streetNameCz" text, "streetNameEn" text, "streetNameFi" text);
Thanks for any advice.
Lange.
if you don't want use crosstab you simple do aggregations:
SELECT addressid,
MAX( CASE WHEN languagecode = 'cz' THEN name END ) as lng_cz,
MAX( CASE WHEN languagecode = 'en' THEN name END ) as lng_en,
MAX( CASE WHEN languagecode = 'fi' THEN name END ) as lng_fi
FROM YourTable
GROUP BY addressid

postgresql crosstab simple example

I got a key-value based table where each key-value pair is assigned to an entity which is identified by an id:
|_id__|_key_______|_value_|
| 123 | FIRSTNAME | John |
| 123 | LASTNAME | Doe |
And I want to transform it a structre like this:
|_id__|_firstName_|_lastName_|
| 123 | John | Doe |
I suppose one can use postgres build in crosstab function to do it.
Can you show me how to do it and explain why it works?
First of all activate the build in tablefunc-extension:
CREATE EXTENSION tablefunc;
Then create table and add sample data:
CREATE TABLE example (
id int,
key text,
value text
);
INSERT INTO example VALUES
(123, 'firstName', 'John'),
(123, 'lastName', 'Doe');
Now lets prepare the crosstab statment:
SELECT *
FROM example
ORDER BY id ASC, key ASC;
Its important to have the ORDER BY here.
Result:
|_id__|_key_______|_value_|
| 123 | FIRSTNAME | John |
| 123 | LASTNAME | Doe |
Solution
Now crosstab creates the table as we want:
SELECT *
FROM crosstab(
'SELECT *
FROM example
ORDER BY id ASC, key ASC;'
) AS ct(id INT, firstname TEXT, lastname TEXT);
Result:
|_id__|_firstName_|_lastName_|
| 123 | John | Doe |
How it works #1
To however understand how it works I found it easiest to just change the ORDER BY and see what happens:
SELECT *
FROM crosstab(
'SELECT *
FROM example
ORDER BY id ASC, key DESC;'
) AS ct(id INT, firstname TEXT, lastname TEXT);
Result:
|_id__|_firstName_|_lastName_|
| 123 | Doe | John |
As we changed the sorting of the key, the crosstab function sees the keys sorted in the other direction, thus reversing the generated columns.
How it works #2
Another thing that helped me understand how it works: the column definition is all about positions:
SELECT *
FROM crosstab(
'SELECT *
FROM example
ORDER BY id ASC, key ASC;'
) AS ct(blablafirst INT, blablasecond TEXT, blablathird TEXT);
Result
|_blablafirst__|_blablasecond_|_blablathird_|
| 123 | John | Doe |

PostgreSQL Hierarchical, category tree

ENV : postgresql-8.4
I'm trying to build a category tree . Basically I'm expecting a final output such :
categoryName
categoryPath
leafcategory
e.g. :
Digital Camera
Electronics ::: Digital Camera
true
The table structure is
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
categoryid bigint,
categoryparentid bigint,
categoryname text,
status integer DEFAULT 0,
lang text,
eysiteid text,
country text,
tempid text,
leafcategory boolean
);
So far I've got this but is not working. Any help would be highly appreciated :
WITH RECURSIVE tree (CategoryID, CategoryParentID, CategoryName, category_tree, depth)
AS (
SELECT
CategoryID,
CategoryParentID,
CategoryName,
CategoryName AS category_tree,
0 AS depth
FROM categories
WHERE CategoryParentID IS NULL
UNION ALL
SELECT
c.CategoryID,
c.CategoryParentID,
c.CategoryName,
tree.category_tree || '/' || c.CategoryName AS category_tree,
depth+1 AS depth
FROM tree
JOIN categories c ON (tree.category_tree = c.CategoryParentID)
)
SELECT * FROM tree ORDER BY category_tree;
Sample from database
cat=> select * from categories;
id | categoryid | categoryparentid | categoryname | status | lang | eysiteid | country | tempid | leafcategory
-------+------------+------------------+--------------------------------+--------+------+------------+---------+--------+--------------
1 | -1 | 0 | Root | 1 | en | 0 | us | | f
2 | 20081 | -1 | Antiques | 1 | en | 0 | us | | f
17 | 1217 | 20081 | Primitives | 0 | en | 0 | us | | t
23 | 22608 | 20081 | Reproduction Antiques | 0 | en | 0 | us | | t
24 | 12 | 20081 | Other | 0 | en | 0 | us | | t
25 | 550 | -1 | Art | 1 | en | 0 | us | | f
29 | 2984 | -1 | Baby | 1 | en | 0 | us | | f
It appears you were joining on the wrong field.
-- create some test data
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE categories
-- ( id SERIAL PRIMARY KEY
( categoryid SERIAL PRIMARY KEY
, categoryparentid bigint REFERENCES categories(categoryid)
, categoryname text
-- , status integer DEFAULT 0
-- , lang text
-- , ebaysiteid text
-- , country text
-- , tempid text
-- , leafcategory boolean
);
INSERT INTO categories(categoryid,categoryparentid) SELECT gs, 1+(gs/6)::integer
FROM generate_series(1,50) gs;
UPDATE categories SET categoryname = 'Name_' || categoryid::text;
UPDATE categories SET categoryparentid = NULL WHERE categoryparentid <= 0;
UPDATE categories SET categoryparentid = NULL WHERE categoryparentid >= categoryid;
WITH RECURSIVE tree (categoryid, categoryparentid, categoryname, category_tree, depth)
AS (
SELECT
categoryid
, categoryparentid
, categoryname
, categoryname AS category_tree
, 0 AS depth
FROM categories
WHERE categoryparentid IS NULL
UNION ALL
SELECT
c.categoryid
, c.categoryparentid
, c.categoryname
, tree.category_tree || '/' || c.categoryname AS category_tree
, depth+1 AS depth
FROM tree
JOIN categories c ON tree.categoryid = c.categoryparentid
)
SELECT * FROM tree ORDER BY category_tree;
EDIT: the other ("non-function") notation for recursive seems to work better:
WITH RECURSIVE tree AS (
SELECT
categoryparentid AS parent
, categoryid AS self
, categoryname AS treepath
, 0 AS depth
FROM categories
WHERE categoryparentid IS NULL
UNION ALL
SELECT
c.categoryparentid AS parent
, c.categoryid AS self
, t.treepath || '/' || c.categoryname AS treepath
, depth+1 AS depth
FROM categories c
JOIN tree t ON t.self = c.categoryparentid
)
SELECT * FROM tree ORDER BY parent,self
;
UPDATE: in the original query, you should replace
WHERE CategoryParentID IS NULL
by:
WHERE CategoryParentID = 0
or maybe even:
WHERE COALESCE(CategoryParentID, 0) = 0
Have a look at this gist it is more or less what you want to do. In your case I would better have used LTree materialized path Postgresql's extension.