join with MULTIPLE rows for fulltext search - sql

please read carefully because my english is not good, and the question has not an easy answer!
I have a simple structure like this:
table nodes
------------------------
nodeId | name
1 | Mazda Miata 2.0
2 | Red Cars
3 | Mazda Cars
4 | Sport cars
table associations
------------------------
nodeId | hasNodeId
1 | 2
1 | 3
1 | 4
3 | 4
3 | 1
and I want to select any row of the first table joining (in the same row) all the associated rows, according to what is specified by the table "associations"
the problem is that joining one node with one single node gives me the fulltext relevance of a SINGLE associated node: what I want is the relevance of ALL associated NODES
thank you
edit, the join result should be as you imagine like this, using the fulltext search:
nodeId | name | joinedName | fulltextRelev
1 | Mazda Miata 2.0 | Red Cars | 4.2
1 | Mazda Miata 2.0 | Mazda Cars | 2.3
1 | Mazda Miata 2.0 | Sport Cars | 3.2
the previous one is an abstract table, what i really want is to get unique/distinct nodeId, with the sum of the fulltextRelevance of the previous table... like this:
nodeId | name | fulltextRelevSUM
1 | Mazda Miata 2.0 | 9.7
9.7 = 4.2 + 2.3 + 3.2

You just have to group by your nodeId like this:
SELECT
nodeId, name, SUM(fulltextRelevSUM) AS fulltextRelevSum
FROM
/*your already done work here*/
GROUP BY nodeId

SELECT
n.nodeID,
n.name,
n2.name as joinedName,
MATCH(n.name) AGAINST(n2.name) AS fulltextRelev
FROM NODES n
LEFT OUTER JOIN ASSOCIATIONS a
ON n.nodeID = a.nodeID
LEFT OUTER JOIN nodes n2
ON n2.NODE_ID = a.hasNodeID
WHERE n.nodeID = 1
I dont fully understand your text relevance part. can you explain it further? The above query will get you the desired first 4 rows, the query on the second part should be easy

Related

Find records which have multiple occurrences in another table array (postgres)

I have a table which has records in array. Also there is another table which have single string records. I want to get records which have multiple occurrences in another table. Following are tables;
Vehicle
veh_id | vehicle_types
-------+---------------------------------------
1 | {"byd_tang","volt","viper","laferrari"}
2 | {"volt","viper"}
3 | {"byd_tang","sonata","jaguarxf"}
4 | {"swift","teslax","mirai"}
5 | {"volt","viper"}
6 | {"viper","ferrariff","bmwi8","viper"}
7 | {"ferrariff","viper","viper","volt"}
vehicle_names
id | vehicle_name
-----+-----------------------
1 | byd_tang
2 | volt
3 | viper
4 | laferrari
5 | sonata
6 | jaguarxf
7 | swift
8 | teslax
9 | mirai
10 | ferrariff
11 | bmwi8
I have a query which can give output what I expect but its not optimal and may be its expensive query.
This is the query:
select veh_name
from vehicle_names dsb
where (select count(*) from vehicle dsd
where dsb.veh_name = ANY (dsd.veh_types)) > 1
The output should be:
byd_tang
volt
viper
One option would be an aggregation query:
SELECT
vn.id,
vn.veh_name
FROM vehicle_names vn
INNER JOIN vehicle v
ON vn. veh_name = ANY (v.veh_types)
GROUP BY
vn.id,
vn.veh_name
HAVING
COUNT(*) > 1;
This only counts a vehicle name which appears in two or more records in the other table. It would not pick up, for example, a single vehicle record with the same name appearing two or more times.

In a query (no editing of tables) how do I join data without any similarities?

I Have a query that finds a table, here's an example one.
Name |Age |Hair |Happy | Sad |
Jon | 15 | Black |NULL | NULL|
Kyle | 18 |Blonde |YES |NULL |
Brad | 17 | Blue |NULL |YES |
Name and age come from one table in a database, hair color comes from a second which is joined, and happy and sad come from a third table.My goal would be to make the first line of the chart like this:
Name |Age |Hair |Happy |Sad |
Jon | 15 |Black |Yes |Yes |
Basically I want to get rid of the rows under the first and get the non NULL data joined to the right. The problem is that there is no column where the Yes values are on the Jon row, so I have no idea how to get them there. Any suggestions?
PS. With the data I am using I can't just put a 'YES' in the 'Jon' row and call it a day, I would need to find the specific value from the lower rows and somehow get that value in the boxes that are NULL.
Do you just want COALESCE()?
COALESCE(Happy, 'Yes') as happy
COALESCE() replaces a NULL value with another value.
If you want to join on a NULL value work with nested selects. The inner select gets an Id for NULLs, the outer select joins
select COALESCE(x.Happy, yn_table.description) as happy, ...
from
(select
t1.Happy,
CASE WHEN t1.Happy is null THEN 1 END as happy_id
from t1 ...) x
left join yn_table
on x.xhappy_id = yn_table.id
If you apply an ORDER BY to the query, you can then select the first row relative to this order with WHERE rownum = 1. If you don't apply an ORDER BY, then the order is random.
After reading your new comment...
the sense is that in my real data the yes under the other names will be a number of a piece of equipment. I want the numbers of the equipment in one row instead of having like 8 rows with only 4 ' yes' values and the rest null.
... I come to the conclusion that this a XY problem.
You are asking about a detail you think will solve your problem, instead of explaining the problem and asking how to solve it.
If you want to store several pieces of equipment per person, you need three tables.
You need a Person table, an Article table and a junction table relating articles to persons to equip them. Let's call this table Equipment.
Person
------
PersonId (Primary Key)
Name
optional attributes like age, hair color
Article
-------
ArticleId (Primary Key)
Description
optional attributes like weight, color etc.
Equipment
---------
PersonId (Primary Key, Foreign Key to table Person)
ArticleId (Primary Key, Foreign Key to table Article)
Quantity (optional, if each person can have only one of each article, we don't need this)
Let's say we have
Person: PersonId | Name
1 | Jon
2 | Kyle
3 | Brad
Article: ArticleId | Description
1 | Hat
2 | Bottle
3 | Bag
4 | Camera
5 | Shoes
Equipment: PersonId | ArticleId | Quantity
1 | 1 | 1
1 | 4 | 1
1 | 5 | 1
2 | 3 | 2
2 | 4 | 1
Now Jon has a hat, a camera and shoes. Kyle has 2 bags and one camera. Brad has nothing.
You can query the persons and their equipment like this
SELECT
p.PersonId, p.Name, a.ArticleId, a.Description AS Equipment, e.Quantity
FROM
Person p
LEFT JOIN Equipment e
ON p.PersonId = e.PersonId
LEFT JOIN Article a
ON e.ArticleId = a.ArticleId
ORDER BY p.Name, a.Description
The result will be
PersonId | Name | ArticleId | Equipment | Quantity
---------+------+-----------+-----------+---------
3 | Brad | NULL | NULL | NULL
1 | Jon | 4 | Camera | 1
1 | Jon | 1 | Hat | 1
1 | Jon | 5 | Shoes | 1
2 | Kyle | 3 | Bag | 2
2 | Kyle | 4 | Camera | 1
See example: http://sqlfiddle.com/#!4/7e05d/2/0
Since you tagged the question with the oracle tag, you could just use NVL(), which allows you to specify a value that would replace a NULL value in the column you select from.
Assuming that you want the 1st row because it contains the smallest age:
- wrap your query inside a CTE
- in another CTE get the 1st row of the query
- in another CTE get the max values of Happy and Sad of your query (for your sample data they both are 'YES')
- cross join the last 2 CTEs.
with
cte as (
<your query here>
),
firstrow as (
select name, age, hair from cte
order by age
fetch first row only
),
maxs as (
select max(happy) happy, max(sad) sad
from cte
)
select f.*, m.*
from firstrow f cross join maxs m
You can try this:
SELECT A.Name,
A.Age,
B.Hair,
C.Happy,
C.Sad
FROM A
INNER JOIN B
ON A.Name = B.Name
INNER JOIN C
ON A.Name = B.Name
(Assuming that Name is the key columns in the 3 tables)

How do I query for records that all have the same relationships (MS Access)?

I'm trying to query for records that share common relationships. In order to avoid gratuitous context, here is a hypothetical example from my favorite old-school Nintendo game:
Consider a table of boxers:
tableBoxers
ID | boxerName
----------------
1 | Little Mac
2 | King Hippo
3 | Von Kaiser
4 | Don Flamenco
5 | Bald Bull
Now I have a relationship table that links them together
boxingMatches
boxerID1 | boxerID2
-----------------------
1 | 3
2 | 5
2 | 4
5 | 1
4 | 1
Since I don't want to discriminate between ID1 and ID2, I create a query that UNIONs them together:
SELECT firstID AS boxerID1, secondID AS boxerID2 FROM
(
SELECT boxerID1 AS firstID, boxerID2 AS boxerID FROM boxingMatches
UNION ALL
SELECT boxerID2 AS firstID, boxerID1 AS secondID FROM boxingMatches
) ORDER BY firstID, secondID
I get:
queryBoxingMatches
boxerID1 | boxerID2
-----------------------
1 | 3
1 | 4
1 | 5
2 | 4
2 | 5
3 | 1
4 | 1
4 | 2
5 | 1
5 | 2
Now I have VBA script where a user can select the boxers he's interested in. Let's say he selects Little Mac (1) and King Hippo (2). This gets appended into a temporary table:
summaryRequest
boxerID
--------
1
2
Using table [summaryRequest] and [queryBoxingMatches], how do I find out whom Little Mac (1) and King Hippo (2) have similarly fought against? The result should be Bald Bull (5) and Don Flamenco (4).
Bear in mind that [summaryRequest] could have 0 or more records. I have considered an INTERSECT, but I'm not sure that's the right function for this. I've tried using COUNT numerous ways, but it gives undesired data when there are multiple relationships (e.g. if Little Mac fought Bald Bull twice and King Hippo only fought him once).
I can't help but feel like the answer is plain and simple and I'm just overthinking it. Any help is appreciated. Thanks.
Not sure if that works like this in MS Access:
SELECT boxerID2, COUNT(*) as cnt
FROM queryBoxingMatches
WHERE boxerID1 IN (SELECT boxerID FROM summaryRequest)
GROUP BY boxerID2
HAVING COUNT(DISTINCT boxerID1) = (SELECT COUNT(DISTINCT boxerID)
FROM summaryRequest)
Okay, I think I found the answer:
SELECT boxerID2 FROM
(
SELECT boxerID2, COUNT(boxerID2) AS getCount FROM queryBoxingMatches
WHERE boxerID1 IN (SELECT ID FROM summaryRequest)
GROUP BY boxerID2
)
WHERE getCount = (SELECT COUNT(*) FROM summaryRequest)
It's a play off of COUNT(), which I don't like because COUNT() doesn't guarantee a full-fledged relationship--just a pattern.

Value in one field as lookup from same table

I'm certain this is very easy, but I am very poor at database stuff...
I have the following table in access 2003:
title | id
/root | 1
/root/x | 2
/root/x/y | 3
/root/x/y/z | 4
/root/x/a | 5
/root/x/a/b | 6
i.e. a bunch of nodes and id numbers - you can see that /root/x is the parent of /root/x/y. I'd like to create another table which has a list of all the nodes, along with the id's of their parents. i.e:
id | parent id
1 | -
2 | 1
3 | 2
4 | 3
5 | 2
6 | 5
The follwing will give me the id and the value of the parent:
select id, left(c.title, instrrev(c.title, "/")-1) as parentValue from nodeIDs
yields
id | parentNode
1 |
2 | /root
3 | /root/x
4 | /root/x/y
5 | /root/x
6 | /root/x/a
What is the extra step needed to return the id's of those parent nodes, rather than their values, i.e, return '1' instead of '/root' in that last table?
Many thanks
Something like this perhaps:
select c.id,
left(c.title, instrrev(c.title, "/")-1) as parentValue
, p.id as parentID
from nodeIDs c
left join
nodeIDs p
on left(c.title, instrrev(c.title, "/")-1) = p.title
Something along these lines, I think.
select t1.id,
left(t1.title, instrrev(t1.title, "/")-1) as parentNode,
t2.id as parentID
from nodeIDs t1
inner join nodeIDs t2 on (left(t1.title, instrrev(t1.title, "/")-1)) = t2.title
I don't have any easy way to test this. But the basic idea is that, having derived the title of the parent node, you can do an inner join on it to get the associated id number.

Advance Query with Join

I'm trying to convert a product table that contains all the detail of the product into separate tables in SQL. I've got everything done except for duplicated descriptor details.
The problem I am having all the products have size/color/style/other that many other products contain. I want to only have one size or color descriptor for all the items and reuse the "ID" for all the product which I believe is a Parent key to the Product ID which is a ...Foreign Key. The only problem is that every descriptor would have multiple Foreign Keys assigned to it. So I was thinking on the fly just have it skip figuring out a Foreign Parent key for each descriptor and just check to see if that descriptor exist and if it does use its Key for the descriptor.
Data Table
PI Colo Sz OTHER
1 | Blue | 5 | Vintage
2 | Blue | 6 | Vintage
3 | Blac | 5 | Simple
4 | Blac | 6 | Simple
===================================
Its destination table is this
===================================
DI Description
1 | Blue
2 | Blac
3 | 5
4 | 6
6 | Vintage
7 | Simple
=============================
Select Data.Table
Unique.Data.Table.Colo
Unique.Data.Table.Sz
Unique.Data.Table.Other
=======================================
Then the dual part of the questions after we create all the descriptors how to do a new query and assign the product ID to the descriptors.
PI| DI
1 | 1
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
By figuring out how to do this I should be able to duplicate this pattern for all 300 + columns in the product. Some of these fields are 60+ characters large so its going to save a ton of space.
Do I use a Array?
Okay, if I understand you correctly, you want all unique attributes converted from columns into rows in a single table (detailstable) that has an id and a description field:
Assuming the schema:
datatable
------------------
PI [PK]
Colo
Sz
OTHER
detailstable
------------------
DI [PK]
Description
You can first get all of the unique attributes into its own table with:
INSERT INTO detailstable (Description)
SELECT
a.description
FROM
(
SELECT DISTINCT Colo AS description
FROM datatable
UNION
SELECT DISTINCT Sz AS description
FROM datatable
UNION
SELECT DISTINCT OTHER AS description
FROM datatable
) a
Then to link up the datatable to the detailstable, I'm assuming you have a cross-reference table defined like:
datadetails
------------------
PI [PK]
DI [PK]
You can then do:
INSERT INTO datadetails (PI, DI)
SELECT
a.PI
b.DI
FROM
datatable a
INNER JOIN
detailstable b ON b.Description IN (a.Colo, a.Sz, a.OTHER)
I reckon you want to split description table for different categories, like - colorDescription, sizeDescription etc.
If that is not practical then I would recommend having an extra column showing an category attribute:
DI Description Category
1 | Blue | Color
2 | Blac | Color
3 | 5 | Size
4 | 6 | Size
6 | Vintage | Other
7 | Simple | Other
And then have primary key in this table as combination of ID and Category column.
This will have less chances for injecting any data errors. It will be also easy to track that down.