I am currently executing a code, trying to create tables:
cur.executescript('''
CREATE TABLE User(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE ,
name TEXT, email_id TEXT);
CREATE TABLE Courses(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
course_name TEXT);
CREATE TABLE Member(
user_id INTEGER, course_id INTEGER, role INTEGER)/*student-0 teacher 1*/
PRIMARY KEY(user_id, course_id);
''')
It gives me this error:
File "E:\python_folder_practice_app_programming\SQLite\beginner_pro_db\beginner_pro_db.py", line 18, in
cur.executescript('''
sqlite3.OperationalError: near "PRIMARY": syntax error
Can someone help me debug this?
This is the problematic statement
CREATE TABLE Member(
user_id INTEGER, course_id INTEGER, role INTEGER)/*student-0 teacher 1*/
PRIMARY KEY(user_id, course_id);
Your primary key constraint should be inside the parens (and separated by comma)
Like this (I've broken it into several lines for readability)
CREATE TABLE Member(
user_id INTEGER,
course_id INTEGER,
role INTEGER, /*student-0 teacher 1*/
PRIMARY KEY(user_id, course_id)
);
See examples here https://www.sqlitetutorial.net/sqlite-create-table/
Related
I am trying the following codes to create a keyspace and a table inside of it:
CREATE KEYSPACE IF NOT EXISTS books WITH REPLICATION = { 'class': 'SimpleStrategy',
'replication_factor': 3 };
CREATE TABLE IF NOT EXISTS books (
id UUID PRIMARY KEY,
user_id TEXT UNIQUE NOT NULL,
scale TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT NOT NULL,
reward map<INT,TEXT> NOT NULL,
image_url TEXT NOT NULL,
video_url TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
But I do get:
SyntaxException: line 2:10 no viable alternative at input 'UNIQUE'
(...NOT EXISTS books ( id [UUID] UNIQUE...)
What is the problem and how can I fix it?
I see three syntax issues. They are mainly related to CQL != SQL.
The first, is that NOT NULL is not valid at column definition time. Cassandra doesn't enforce constraints like that at all, so for this case, just get rid of all of them.
Next, Cassandra CQL does not allow default values, so this won't work:
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Providing the current timestamp for created_at is something that will need to be done at write-time. Fortunately, CQL has a few of built-in functions to make this easier:
INSERT INTO books (id, user_id, created_at)
VALUES (uuid(), 'userOne', toTimestamp(now()));
In this case, I've invoked the uuid() function to generate a Type-4 UUID. I've also invoked now() for the current time. However now() returns a TimeUUID (Type-1 UUID) so I've nested it inside of the toTimestamp function to convert it to a TIMESTAMP.
Finally, UNIQUE is not valid.
user_id TEXT UNIQUE NOT NULL,
It looks like you're trying to make sure that duplicate user_ids are not stored with each id. You can help to ensure uniqueness of the data in each partition by adding user_id to the end of the primary key definition as a clustering key:
CREATE TABLE IF NOT EXISTS books (
id UUID,
user_id TEXT,
...
PRIMARY KEY (id, user_id));
This PK definition will ensure that data for books will be partitioned by id, containing multiple user_id rows.
Not sure what the relationship is between books and users is, though. If one book can have many users, then this will work. If one user can have many books, then you'll want to switch the order of the keys to this:
PRIMARY KEY (user_id, id));
In summary, a working table definition for this problem looks like this:
CREATE TABLE IF NOT EXISTS books (
id UUID,
user_id TEXT,
scale TEXT,
title TEXT,
description TEXT,
reward map<INT,TEXT>,
image_url TEXT,
video_url TEXT,
created_at TIMESTAMP,
PRIMARY KEY (id, user_id));
Is there there any way to query on a SET type(or MAP/LIST) to find does it contain a value or not?
Something like this:
CREATE TABLE test.table_name(
id text,
ckk SET<INT>,
PRIMARY KEY((id))
);
Select * FROM table_name WHERE id = 1 AND ckk CONTAINS 4;
Is there any way to reach this query with YCQL api?
And can we use a SET type in SECONDRY INDEX?
Is there any way to reach this query with YCQL api?
YCQL does not support the CONTAINS keyword yet (feel free to open an issue for this on the YugabyteDB GitHub).
One workaround can be to use MAP<INT, BOOLEAN> instead of SET<INT> and the [] operator.
For instance:
CREATE TABLE test.table_name(
id text,
ckk MAP<int, boolean>,
PRIMARY KEY((id))
);
SELECT * FROM table_name WHERE id = 'foo' AND ckk[4] = true;
And can we use a SET type in SECONDRY INDEX?
Generally, collection types cannot be part of the primary key, or an index key.
However, "frozen" collections (i.e. collections serialized into a single value internally) can actually be part of either primary key or index key.
For instance:
CREATE TABLE table2(
id TEXT,
ckk FROZEN<SET<INT>>,
PRIMARY KEY((id))
) WITH transactions = {'enabled' : true};
CREATE INDEX table2_idx on table2(ckk);
Another option is to use with compound primary key and defining ckk as clustering key:
cqlsh> CREATE TABLE ybdemo.tt(id TEXT, ckk INT, PRIMARY KEY ((id), ckk)) WITH CLUSTERING ORDER BY (ckk DESC);
cqlsh> SELECT * FROM ybdemo.tt WHERE id='foo' AND ckk=4;
create table seller(
seller_id int primary key,
seller_name text,
seller_email set<text>,
seller_address map<text>,
seller_phone list<text>,
product_id int,
product_title_text,
product_description text,
product_trackno int,
product_bidoption text,
bid_startdate date,
bid_closedate date,
bid_startprice int,
bid_withdrawdate date);
SyntaxException: line 1:110 mismatched input '>' expecting ',' (...<text>,
seller_address map<text[>],...)
What changes should be made in order to execute?
Of course you can, with some adjustments:
1) It helps if the type of a column isn't linked to the column name by an underscore. Instead of:
product_title_text,
This will work:
product_title text,
2) You'll also need to provide both types for the map collection. Instead of:
seller_address map<TEXT>,
This will work:
seller_address map<TEXT,TEXT>,
Full CQL:
create table seller(
seller_id int primary key,
seller_name text,
seller_email set<TEXT>,
seller_address map<TEXT,TEXT>,
seller_phone list<TEXT>,
product_id int,
product_title text,
product_description text,
product_trackno int,
product_bidoption text,
bid_startdate date,
bid_closedate date,
bid_startprice int,
bid_withdrawdate date);
Also, are you really only ever going to query this table by seller_id? If not, you may want to rethink the primary key definition.
I have a univerity assignment that consists in working with CQL and Cassandra.
In the first part of the assignment I have to "identify the
reference logical aggregates, thus providing a row-oriented view of schema information, and point out attributes which model relationships", but I don't understand what is a "reference logical aggregate".
The schema is the following (it's not created by me, I downloaded it with the assignment):
DROP KEYSPACE gameindustry;
CREATE KEYSPACE gameindustry WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
USE gameindustry;
CREATE TYPE fullname (
firstname text,
lastname text
);
CREATE TABLE games (
name text PRIMARY KEY,
description text,
tags set<text>
);
CREATE TABLE tags (
tag text PRIMARY KEY,
games set<text>
);
CREATE TABLE users (
email text PRIMARY KEY,
password text,
name fullname,
notes text,
games set<text>
);
CREATE TABLE user_games (
user text,
game text,
PRIMARY KEY (user, game)
);
CREATE TABLE friends (
user text,
friend text,
PRIMARY KEY (user, friend)
);
CREATE TABLE matches (
user text,
game text,
when timestamp,
score int,
PRIMARY KEY (game, when, user),
);
I have the following format in json to store lawyers, I have doubts how to model in postgres the field "specialties" which has array of object each one with a title and a subarrays of subspecialties:
{
"id": 1,
"name": "John Johnson Johannes",
"gender": "f",
"specialties": [
{
"specialty": "Business law",
"sub-specialties": [
"Incorporation",
"Taxes",
"Fusions"
]
},
{
"specialty": "Criminal law",
"sub-specialties": [
"Property offenses",
"Personal offenses",
"Strict liability"
]
}
]
}
And I have made this lawyers table in Postgres:
DROP DATABASE IF EXISTS lawyers_db;
CREATE DATABASE lawyers_db;
\c lawyers_db;
CREATE TYPE gen AS ENUM ('f', 'm');
CREATE TABLE lawyers_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR,
gender gen
);
INSERT INTO lawyers_tb (name, gender)
VALUES ('John Doe', 'm');
I'm using some node.js libraries that when I read data from Postgres table it returns the data as a JSON, so I would like to keep the relational model without using JSONb to store as a document my lawyers.
Is it possible to achieve what I want without using JSONb type?
Forget about objects for a minute and really think through what your data are and how they relate to each other (we are after all using a relational database).
What you have here is simply a relationship.
You have lawyers and you have specialties. The relationship is that lawyers have specialties and specialties belong to lawyers (an n-to-n relationship) and the same goes for the relationship between specialties and subspecialties (n-to-n).
First, lets do the simpler structure of a 1-to-n relationship:
CREATE TABLE lawyers_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR,
gender gen
);
CREATE TABLE specialties_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR,
lawyer_ID INTEGER
);
CREATE TABLE subspecialties_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR,
specialty_ID INTEGER
);
This works but results in duplicates because each specialty can only belong to one lawyer thus if two lawyers specialise in "Business law" you'd have to define "Business law" twice. Worse, for each specialty you also have to duplicate subspecialties.
The solution is a join table (also called a map/mapping table):
CREATE TABLE lawyers_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR,
gender gen
);
CREATE TABLE lawyer_specialties_tb (
name VARCHAR,
lawyer_ID INTEGER,
specialty_ID INTEGER
);
CREATE TABLE specialties_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR
);
CREATE TABLE specialty_subspecialties_tb (
name VARCHAR,
specialty_ID INTEGER,
subspecialty_ID INTEGER
);
CREATE TABLE subspecialties_tb (
ID SERIAL PRIMARY KEY,
name VARCHAR
);
This way each specialty can belong to more than one lawyer (true n-to-n relationship) and each subspecialty can belong to more than one specialty.
You can use joins to fetch the whole dataset:
SELECT lawyers_tb.name as name,
lawyers_tb.gender as gender,
specialties_tb.name as specialty,
subspecialties_tb.name as subspecialty
FROM lawyers_tb LEFT JOIN lawyer_specialties_tb
ON lawyers_tb.ID=lawyer_specialties_tb.lawyer_ID
LEFT JOIN specialties_tb
ON specialties_tb.ID=lawyer_specialties_tb.specialty_ID
LEFT JOIN specialty_subspecialties_tb
ON specialties_tb.ID=specialty_subspecialties_tb.specialty_ID
Yes, it's a bit more complicated to query but the structure allows you to maintain each dataset individually and defines the proper relationships between them.
You may also want to define the keys in the join tables as foreign keys to enforce correctness of the dataset.