How to find if a value exists within a VARRAY

2020-02-15 06:42发布

I've created a VARRAY within a table (below) I would like to query whether or not a Title has a particular theme, eg. Show 'Action' games. I'm not to sure how to go about this...

CREATE OR REPLACE TYPE Theme_Game AS OBJECT
(Theme VARCHAR(20));
/ 
CREATE OR REPLACE TYPE Theme_Type AS VARRAY(3) OF Theme_Game;
/
CREATE OR REPLACE TYPE Game_Type AS OBJECT
(Title VARCHAR2(50),
GameTheme Theme_Type);
/
CREATE TABLE Game_Table of Game_Type
/
INSERT INTO Game_Table
VALUES('Star Wars' ,(Theme_Type(Theme_Game('Action'), Theme_Game('FPS'))))
/

3条回答
Explosion°爆炸
2楼-- · 2020-02-15 06:52

For multiple themes you could do something like

select g.Title
from game_table g, table(g.gameTheme) t
where t.Theme in ('FPS','Action')
group by g.Title having count(0) = 2;

This could also allow you to do things like get titles with exactly n matches, at least n matches, at most n matches...

查看更多
beautiful°
3楼-- · 2020-02-15 07:09

You can use a collection and then compare multiple items using the SUBMULTISET operator:

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE OR REPLACE TYPE Theme_Game AS OBJECT
(Theme VARCHAR(20));
/ 
CREATE OR REPLACE TYPE Theme_Type AS TABLE OF Theme_Game;
/
CREATE OR REPLACE TYPE Game_Type AS OBJECT(
  Title VARCHAR2(50),
  GameTheme Theme_Type
);
/
CREATE TABLE Game_Table of Game_Type
NESTED TABLE GameTheme STORE AS GameTheme_Tab
/
INSERT INTO Game_Table
VALUES('Star Wars' ,(Theme_Type(Theme_Game('Action'), Theme_Game('FPS'))))
/

Query 1:

SELECT *
FROM   game_table
WHERE  Theme_Type(Theme_Game('Action'), Theme_Game('FPS'))
       SUBMULTISET OF GameTheme

Results:

|     TITLE |                                             GAMETHEME |
|-----------|-------------------------------------------------------|
| Star Wars | oracle.sql.STRUCT@67e8dc0f,oracle.sql.STRUCT@795b6d4c |

However, why are you using the Theme_Game object when it only has a single VARCHAR2 attribute? You can just use a VARRAY(3) OF VARCHAR2(20) or TABLE OF VARCHAR2(20) without the intermediate object:

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE OR REPLACE TYPE Varchar20List AS TABLE OF VARCHAR2(20);
/
CREATE OR REPLACE TYPE Game_Type AS OBJECT(
  Title VARCHAR2(50),
  GameTheme Varchar20List
);
/
CREATE TABLE Game_Table of Game_Type
NESTED TABLE GameTheme STORE AS GameTheme_Tab
/
INSERT INTO Game_Table
VALUES('Star Wars' , Varchar20List('Action', 'FPS'))
/

Query 1:

SELECT *
FROM   game_table
WHERE  Varchar20List('Action','FPS')
       SUBMULTISET OF GameTheme

Results:

|     TITLE |  GAMETHEME |
|-----------|------------|
| Star Wars | Action,FPS |

If you want to do it with VARRAYs then:

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE OR REPLACE TYPE Varchar20List AS VARRAY(3) OF VARCHAR2(20);
/
CREATE OR REPLACE TYPE Game_Type AS OBJECT(
  Title VARCHAR2(50),
  GameTheme Varchar20List
);
/
CREATE TABLE Game_Table of Game_Type
/
INSERT INTO Game_Table
VALUES('Star Wars' , Varchar20List('Action', 'FPS'))
/

Query 1:

SELECT *
FROM   game_table g
WHERE  2 >= ( SELECT COUNT(*)
              FROM   TABLE( g.GameTheme ) a
                     INNER JOIN
                     TABLE( Varchar20List( 'Action', 'FPS' ) ) b
                     ON ( a.COLUMN_VALUE = b.COLUMN_VALUE )
             )

Results:

|     TITLE |  GAMETHEME |
|-----------|------------|
| Star Wars | Action,FPS |

or:

Query 2:

SELECT *
FROM   game_table g
WHERE  2 >= ( SELECT COUNT(*)
              FROM   TABLE( g.GameTheme ) a
              WHERE  a.COLUMN_VALUE IN ( 'Action', 'FPS' )
             )

Results:

|     TITLE |  GAMETHEME |
|-----------|------------|
| Star Wars | Action,FPS |
查看更多
贼婆χ
4楼-- · 2020-02-15 07:10

You need to expose the nested table in the FROM clause using the table() function. You can then reference attributes of the collection:

SQL> select g.title
  2  from game_table g
  3       , table(g.gametheme) gt
  4  where gt.theme = 'Action';

TITLE
--------------------------------------------------
Star Wars

SQL> 

"what if I then needed to retrieve rows with multiple Themes i.e Action, FPS?"

Apologies for the clunky solution but I need to go to work now. I may post a more elegant solution later.

SQL> select * from game_table
  2  /

TITLE
--------------------------------------------------
GAMETHEME(THEME)
--------------------------------------------------------------------------------
Star Wars
THEME_TYPE(THEME_GAME('Action'), THEME_GAME('FPS'))

Uncharted 3
THEME_TYPE(THEME_GAME('Action'), THEME_GAME('Puzzle'))

Commander Cody
THEME_TYPE(THEME_GAME('Fun'), THEME_GAME('Puzzle'))


SQL> select g.title
  2  from game_table g
  3       , table(g.gametheme) gt
  4       , table(g.gametheme) gt1
  5  where gt.theme = 'Action'
  6  and gt1.theme = 'FPS' ;

TITLE
--------------------------------------------------
Star Wars

SQL> 

This alternative approach won't work with your current type because VARRAY does not support member of. But it would work if the collection was a Nested Table.

 select g.title
  from game_table g
  where  'Action' member of g.gametheme
  and 'FPS' member of g.gametheme
查看更多
登录 后发表回答