Joining Table Relation into one output SQLite - sqlite

I am using sqLite and have two tables Profile and Option. Profiles can vary from options depending on the code (see my example below). Basically users can create custom profiles and hence the code is different.
How can I pull profile options into options list so I have a single output? The only relationship I have is based on code, but some profiles have codes not listed in options. I want codes not listed in Options to also be included and those that exist not be duplicated.
Code below see my comment on expected output.
Also created a fiddle here. http://sqlfiddle.com/#!5/3e657c/1/0
CREATE TABLE profile (id INTEGER PRIMARY KEY, profileId INTEGER, value integer, type text, "name" text, "min" integer, "max" integer, "justment" text, "sortOrder" INTEGER, "code", text);
INSERT INTO "profile" ("id", "profileId", "value", "type", "name", "code") VALUES
('1','1', '0', 'c', 'John', 'test_001'),
('2', '1','0', 'c', 'Peter', 'test_002'),
('3','1', '0', 'c', 'Custom Record', 'cust_003');
CREATE TABLE options (id INTEGER PRIMARY KEY , value integer, type text, "name" text, "min" integer, "max" integer, "justment" text, "sortOrder" INTEGER DEFAULT 0, "code" text);
INSERT INTO "options" ("id", "value", "type", "name", "code") VALUES
('1', '0', 'c', 'John', 'test_001'),
('2', '0', 'c', 'Peter', 'test_002'),
('3', '0', 'c', 'Paul', 'test_003'),
('4', '0', 'c', 'Tim', 'test_004');
Expected Output single list no duplicates
|Name|
John
Peter
Paul
Tim
Custom Record
/*
Not sure if this is even possible, but appreciate any insight. Probably going to have to do this with a loop in PHP, but if there is any SQL way it would be appreciated.

You can do it with UNION ALL and NOT EXISTS in the 2nd query:
select id, value, type, name, code from options
union all
select id, value, type, name, code from profile p
where not exists (
select 1 from options o
where p.code = o.code
)
You can change the select list to return the columns that you need.
See the demo.
Results:
| id | value | type | name | code |
| --- | ----- | ---- | ------------- | -------- |
| 1 | 0 | c | John | test_001 |
| 2 | 0 | c | Peter | test_002 |
| 3 | 0 | c | Paul | test_003 |
| 4 | 0 | c | Tim | test_004 |
| 3 | 0 | c | Custom Record | cust_003 |

Related

How to select a limited amount of values in a complex column in Hive?

I have a table with an id, name and proficiency. The proficiency column is of a complex column with map data type. How do I limit the amount of data to 2 shown in the complex map data type?
Example table
ID | name | Proficiency
003 | John | {"Cooking":3, "Talking":6 , "Chopping":8, "Teaching":5}
005 | Lennon | {"Cooking":3, "Programming":6 }
007 | King | {"Chopping":8, "Boxing":5 ,"shooting": 4}
What i want to show after the select statement
ID | name | Proficiency
003 | John | {"Cooking":3, "Talking":6 }
005 | Lennon | {"Cooking":3, "Programming":6 }
007 | King | {"Chopping":8, "Boxing":5 }
For fixed number of map elements required this can be done easily using map_keys() and map_values() functions which return arrays of keys and values, you can access key and value using array index, then assemble map again using map() function:
with MyTable as -------use your table instead of this subquery
(select stack(3,
'003', 'John' , map("Cooking",3, "Talking",6 , "Chopping",8, "Teaching",5),
'005', 'Lennon', map("Cooking",3, "Programming",6 ),
'007', 'King' , map("Chopping",8, "Boxing",5 ,"shooting", 4)
) as (ID, name, Proficiency)
) -------use your table instead of this
select t.ID, t.name,
map(map_keys(t.Proficiency)[0], map_values(t.Proficiency)[0],
map_keys(t.Proficiency)[1], map_values(t.Proficiency)[1]
) as Proficiency
from MyTable t
Result:
t.id t.name proficiency
003 John {"Cooking":3,"Talking":6}
005 Lennon {"Cooking":3,"Programming":6}
007 King {"Boxing":5,"shooting":4}
Map does not guarantee the order by definition, and map_keys, map_values return unordered arrays by definition, but they are in the same order when used in the same subquery, so keys are matching to their corresponding values.

Select several event params in a single row for Firebase events stored in Google BigQuery

I'm trying to perform a very simple query for Firebase events stored in Google BigQuery but I´m not able to find a way to do it.
In the Android app, I´m logging an event like this:
Bundle params = new Bundle();
params.putInt("productID", productId);
params.putInt(FirebaseAnalytics.Param.VALUE, value);
firebaseAnalytics.logEvent("productEvent", params);
So, in BigQuery I have something like this:
___________________ _______________________ ____________________________
| event_dim.name | event_dim.params.key | event_dim.params.int_value |
|___________________|_______________________|____________________________|
| productEvent | productID | 25 |
| |_______________________|____________________________|
| | value | 1253 |
|___________________|_______________________|____________________________|
When I get the data from this table I get two rows:
___________________ _______________________ ____________________________
|event_dim.name | event_dim.params.key | event_dim.params.int_value |
|___________________|_______________________|____________________________|
| productEvent | productID | 25 |
| productEvent | value | 12353 |
But what I really need is a SELECT clause from this table to get the data as below:
___________________ _____________ _________
| name | productID | value |
|___________________|_____________|_________|
| productEvent | 25 | 12353 |
Any idea or suggestion?
You can pivot the values into columns like this
SELECT
event_dim.name as name,
MAX(IF(event_dim.params.key = "productID", event_dim.params.int_value, NULL)) WITHIN RECORD productID,
MAX(IF(event_dim.params.key = "value", event_dim.params.int_value, NULL)) WITHIN RECORD value,
FROM [events]
In case you want to generate this command using SQL, see this solution: Pivot Repeated fields in BigQuery
Using standard SQL (uncheck "Use Legacy SQL" under "Show Options" in the UI), you can express the query as:
SELECT
event_dim.name as name,
(SELECT value.int_value FROM UNNEST(event_dim.params)
WHERE key = "productID") AS productID,
(SELECT value.int_value FROM UNNEST(event_dim.params)
WHERE key = "value") AS value
FROM `dataset.mytable` AS t,
t.event_dim AS event_dim;
Edit: updated example to include int_value as part of value based on the comment below. Here is a self-contained example that demonstrates the approach as well:
WITH T AS (
SELECT ARRAY_AGG(event_dim) AS event_dim
FROM (
SELECT STRUCT(
"foo" AS name,
ARRAY<STRUCT<key STRING, value STRUCT<int_value INT64, string_value STRING>>>[
("productID", (10, NULL)), ("value", (5, NULL))
] AS params) AS event_dim
UNION ALL
SELECT STRUCT(
"bar" AS name,
ARRAY<STRUCT<key STRING, value STRUCT<int_value INT64, string_value STRING>>>[
("productID", (13, NULL)), ("value", (42, NULL))
] AS params) AS event_dim
)
)
SELECT
event_dim.name as name,
(SELECT value.int_value FROM UNNEST(event_dim.params)
WHERE key = "productID") AS productID,
(SELECT value.int_value FROM UNNEST(event_dim.params)
WHERE key = "value") AS value
FROM T AS t,
t.event_dim AS event_dim;

Oracle 11g: Replace part of string using dictionary mapping

Is there any nice trick to change values in string using dictionary mapping? For example I have table1 FIDDLE
+---------------------------+
| ROW1 |
+---------------------------+
| This is an example string |
| This String has typ0s |
+---------------------------+
And some mapping table dict1 FIDDLE:
+-------------------------+
| OLD | NEW |
+-------------------------+
| THIS | THAT |
| IS | ARE |
| EXAMPLE | SOURCE |
| STRING | NUMBER |
+------------+------------+
I need some SELECT statement that will split values in table1.row1 and change words using mapping dictionary dict1 so received values will be ( changing no existing dictionary values to upper is optional):
+---------------------------+
| TRANS_ROW1 |
+---------------------------+
| THAT ARE AN SOURCE NUMBER |
| THAT NUMBER HAS TYP0S |
+---------------------------+
PS. Spliting using REGEXP expression will be so nice..
WITH dict1 AS
(SELECT 'THIS' fr,
'THAT' t
FROM dual
UNION ALL
SELECT 'IS' fr,
'ARE' t
FROM dual
UNION ALL
SELECT 'EXAMPLE' fr,
'SOURCE' t
FROM dual
UNION ALL
SELECT 'STRING' fr,
'NUMBER' t
FROM dual),
table1 AS
(SELECT 'This is an example string' AS str,
1 AS sn
FROM dual
UNION ALL
SELECT 'This String has typ0s' AS str,
2 sn
FROM dual),
src AS
(SELECT regexp_substr(upper(s.str), '[^ ]+', 1, LEVEL) str2,
s.*,
rownum nn
FROM table1 s
CONNECT BY instr(TRIM(' ' FROM str), ' ', 1, LEVEL - 1) > 0
AND PRIOR sn = sn
AND PRIOR dbms_random.value IS NOT NULL),
repl AS
(SELECT nvl2(dict1.t, dict1.t, src.str2) lex,
sn,
nn
FROM src
LEFT JOIN dict1
ON dict1.fr = src.str2)
SELECT listagg(lex, ' ') within GROUP(ORDER BY nn),
sn
FROM repl
GROUP BY sn
It works now as you ask. Enjoy.
EDIT: FIDDLE with solution

Creating a view in a not relational database

I had an issue and I hope that someone could help me out. In fact, I work on a poorly designed database and I have no control to change things in it. I have a table "Books", and each book can have one or more author. Unfortunately the database is not fully relational (please don't ask me why because I am asking the same question from the beginning). In the table "Books" there is a field called "Author_ID" and "Author_Name", so when a book was written by 2 or 3 authors their IDs and Their names will be concatenated in the same record separated by an star. Here is a demonstration:
ID_BOOK | ID_AUTHOR | NAME AUTHOR | Adress | Country |
----------------------------------------------------------------------------------
001 |01 | AuthorU | AdrU | CtryU |
----------------------------------------------------------------------------------
002 |02*03*04 | AuthorX*AuthorY*AuthorZ | AdrX*NULL*AdrZ | NULL*NULL*CtryZ |
----------------------------------------------------------------------------------
I need to create a view against this table that would give me this result:
ID_BOOK | ID_AUTHOR | NAME AUTHOR | Adress | Country |
----------------------------------------------------------------------------------
001 |01 | AuthorU | AdrU | CtryU |
----------------------------------------------------------------------------------
002 |02 | AuthorX | AdrX | NULL |
----------------------------------------------------------------------------------
002 |03 | AuthorY | NULL | NULL |
----------------------------------------------------------------------------------
002 |04 | AuthorZ | AdrZ | CtryZ |
----------------------------------------------------------------------------------
I will continue trying to do it and I hope that someone could help me with at least some hints. Many thanks guys.
After I applied the solution given by you guys I got this problem. I am trying to solve it and hopefully you can help me. In fact, when the sql query run, the CLOB fields are disorganized when some of them contain NULL value. The reslut should be like above, but i got the result below:
ID_BOOK | ID_AUTHOR | NAME AUTHOR | Adress | Country |
----------------------------------------------------------------------------------
001 |01 | AuthorU | AdrU | CtryU |
----------------------------------------------------------------------------------
002 |02 | AuthorX | AdrX | CtryZ |
----------------------------------------------------------------------------------
002 |03 | AuthorY | AdrZ | NULL |
----------------------------------------------------------------------------------
002 |04 | AuthorZ | NULL | NULL |
----------------------------------------------------------------------------------
Why does it put the NULL values in the end? Thank you.
in 11g you can use a factored recursive sub query for this:
with data (id_book, id_author, name, item_author, item_name, i)
as (select id_book, id_author, name,
regexp_substr(id_author, '[^\*]+', 1, 1) item_author,
regexp_substr(name, '[^\*]+', 1, 1) item_name,
2 i
from books
union all
select id_book, id_author, name,
regexp_substr(id_author, '[^\*]+', 1, i) item_author,
regexp_substr(name, '[^\*]+', 1, i) item_name,
i+1
from data
where regexp_substr(id_author, '[^\*]+', 1, i) is not null)
select id_book, item_author, item_name
from data;
fiddle
A couple weeks ago I answered a similar question here. That answer has an explanation (I hope) of the general approach so I'll skip the explanation here. This query will do the trick; it uses REGEXP_REPLACE and leverages its "occurrence" parameter to pick the individual author ID's and names:
SELECT
ID_Book,
REGEXP_SUBSTR(ID_Author, '[^*]+', 1, Counter) AS AuthID,
REGEXP_SUBSTR(Name_Author, '[^*]+', 1, Counter) AS AuthName
FROM Books
CROSS JOIN (
SELECT LEVEL Counter
FROM DUAL
CONNECT BY LEVEL <= (
SELECT MAX(REGEXP_COUNT(ID_Author, '[^*]+'))
FROM Books))
WHERE REGEXP_SUBSTR(Name_Author, '[^*]+', 1, Counter) IS NOT NULL
ORDER BY 1, 2
There's a Fiddle with your data plus another row here.
Addendum: OP has Oracle 9, not 11, so regular expressions won't work. Following are instructions for doing the same task without regexes...
Without REGEXP_COUNT, the best way count authors is to count the asterisks and add one. To count asterisks, take the length of the string, then subtract its length when all the asterisks are sucked out of it: LENGTH(ID_Author) - LENGTH(REPLACE(ID_Author, '*')).
Without REGEX_SUBSTR, you need to use INSTR to find the position of the asterisks, and then SUBSTR to pull out the author IDs and names. This gets a little complicated - consider these Author columns from your original post:
Author U
Author X*Author Y*Author Z
AuthorX lies between the beginning the string and the first asterisk.
AuthorY is surrounded by asterisks
AuthorZ lies between the last asterisk and the end of the string.
AuthorU is all alone and not surrounded by anything.
Because of this, the opening piece (WITH AuthorInfo AS... below) adds an asterisk to the beginning and the end so every author name (and ID) is surrounded by asterisks. It also grabs the author count for each row. For the sample data in your original post, the opening piece will yield this:
ID_Book AuthCount ID_Author Name_Author
------- --------- ---------- -------------------------
001 1 *01* *AuthorU*
002 3 *02*03*04* *AuthorX*AuthorY*AuthorZ*
Then comes the join with the "Counter" table and the SUBSTR machinations to pull out the individual names and IDs. The final query looks like this:
WITH AuthorInfo AS (
SELECT
ID_Book,
LENGTH(ID_Author) -
LENGTH(REPLACE(ID_Author, '*')) + 1 AS AuthCount,
'*' || ID_Author || '*' AS ID_Author,
'*' || Name_Author || '*' AS Name_Author
FROM Books
)
SELECT
ID_Book,
SUBSTR(ID_Author,
INSTR(ID_Author, '*', 1, Counter) + 1,
INSTR(ID_Author, '*', 1, Counter+1) - INSTR(ID_Author, '*', 1, Counter) - 1) AS AuthID,
SUBSTR(Name_Author,
INSTR(Name_Author, '*', 1, Counter) + 1,
INSTR(Name_Author, '*', 1, Counter+1) - INSTR(Name_Author, '*', 1, Counter) - 1) AS AuthName
FROM AuthorInfo
CROSS JOIN (
SELECT LEVEL Counter
FROM DUAL
CONNECT BY LEVEL <= (SELECT MAX(AuthCount) FROM AuthorInfo))
WHERE AuthCount >= Counter
ORDER BY ID_Book, Counter
The Fiddle is here
If you have an authors table, you can do:
select b.id_book, a.id_author, a.NameAuthor
from books b left outer join
authors a
on '*'||NameAuthor||'*' like '%*||a.author||'*%'
In addition:
SELECT distinct id_book,
, trim(regexp_substr(id_author, '[^*]+', 1, LEVEL)) id_author
, trim(regexp_substr(author_name, '[^*]+', 1, LEVEL)) author_name
FROM yourtable
CONNECT BY LEVEL <= regexp_count(id_author, '[^*]+')
ORDER BY id_book, id_author
/
ID_BOOK ID_AUTHOR AUTHOR_NAME
------------------------------------
001 01 AuthorU
002 02 AuthorX
002 03 AuthorY
002 04 AuthorZ
003 123 Jane Austen
003 456 David Foster Wallace
003 789 Richard Wright
No REGEXP:
SELECT str, SUBSTR(str, substr_start_pos, substr_end_pos) final_str
FROM
(
SELECT str, substr_start_pos
, (CASE WHEN substr_end_pos <= 0 THEN (Instr(str, '*', 1)-1)
ELSE substr_end_pos END) substr_end_pos
FROM
(
SELECT distinct '02*03*04' AS str
, (Instr('02*03*04', '*', LEVEL)+1) substr_start_pos
, (Instr('02*03*04', '*', LEVEL)-1) substr_end_pos
FROM dual
CONNECT BY LEVEL <= length('02*03*04')
)
ORDER BY substr_start_pos
)
/
STR FINAL_STR
---------------------
02*03*04 02
02*03*04 03
02*03*04 04

sqlite combining select results for searching

Alright so here are my two tables.
CREATE TABLE [cards] (
[id] TEXT PRIMARY KEY,
[game_id] TEXT NOT NULL,
[set_id] TEXT CONSTRAINT [id_set_id] REFERENCES [sets]([id]) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE NOT DEFERRABLE INITIALLY IMMEDIATE,
[name] TEXT NOT NULL,
[image] TEXT NOT NULL);
CREATE TABLE [custom_properties] (
[id] TEXT PRIMARY KEY,
[card_id] TEXT CONSTRAINT [id_card_id] REFERENCES [cards]([id]) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE NOT DEFERRABLE INITIALLY IMMEDIATE,
[game_id] TEXT CONSTRAINT [id_game_id4] REFERENCES [games]([id]) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE NOT DEFERRABLE INITIALLY IMMEDIATE,
[name] TEXT NOT NULL,
[type] INTEGER NOT NULL,
[vint] INTEGER,
[vstr] TEXT);
What I would like to do is to have a search that grabs all the data from the cards row, and then adds the column who's name is (where custom_properties.card_id == cards.id).name.
Then I would like it's value to be vint if type == 1, else vstr.
So, here is an example dataset
cards
|id | game_id | set_id | name | image|
+---+---------+--------+------+------+
| a | asdf | fdsaf |loler | blah |
+------------------------------------+
custom_properties
| id | card_id | game_id | name | type | vint | vstr |
+----+---------+---------+------+------+------+------+
| f | a | asdf | range| 1 | 12 | |
| b | a | asdf | rank | 0 | | face |
+----+---------+---------+------+------+------+------+
the resulting table would look like this, where the columns range and rank are derived from custom_properties.name
|id | game_id | set_id | name | image | range | rank |
+---+---------+--------+------+-------+-------+------+
|a | asdf | fdsaf | loler| blah | 12 | face |
+---+---------+--------+------+-------+-------+------+
try this:
SELECT Cards.id,
Cards.game_id,
Cards.set_id,
Cards.name,
Cards.id,
Cards.image,
CASE
WHEN Custom_Properties.type = 1 THEN
Custom_Properties.vint
ELSE
Custom_Properties.vstr
END as Range
Custom_Properties.vstr as rank
FROM Cards INNER JOIN Custom_Properties
ON Cards.id = Custom_Properties.card_ID
WHERE Cards.Name = 'loller'
It's not actually possible to do this.

Resources