sqlite 2 tables with relationship table - sqlite

I'm working pulling RedHat vulnerability information and I am stuck at the sql query :) Essentially I have 2 tables (cve, errata) where data is kept and a third (references) that is a reference table with ids from tables errata and cve.
What I'm looking to extract is information from both tables, like this:
name_from_errata name_from_cve severity_from_errata releasedata_from_errata
RHSA-2017:0837 CVE-2017-5208 important 2017-03-23...
RHSA-2017:0837 CVE-2017-5332 moderate 2017-03-23...
RHSA-2017:0837 CVE-2017-5333 important ............
RHSA-2017:0837 CVE-2017-6009 important ............
.........................
Thanks!
Mario
For example this link lists 6 vulnerabilities
RedHat Advisory sample
CVE-2017-5208
CVE-2017-5332
CVE-2017-5333
CVE-2017-6009
CVE-2017-6010
CVE-2017-6011
Sqlite3 Database available # cvrf
[localhost cvrf]$ sqlite3 cvrf.db
sqlite> .headers on
sqlite> .mode column
sqlite> .tables
cve errata package relationship`
sqlite> .schema cve
CREATE TABLE "cve" ("id" INTEGER NOT NULL PRIMARY KEY, "name" VARCHAR(255) NOT NULL, "severity" VARCHAR(255), "cvss_score" VARCHAR(255), "publicdate" DATETIME);
CREATE UNIQUE INDEX "cve_name" ON "cve" ("name");`
sqlite> .schema errata
CREATE TABLE "errata" ("id" INTEGER NOT NULL PRIMARY KEY, "name" VARCHAR(255) NOT NULL, "severity" VARCHAR(255), "releasedate" DATETIME);
CREATE UNIQUE INDEX "errata_name" ON "errata" ("name");`
sqlite> .schema relationship
CREATE TABLE "relationship" ("id" INTEGER NOT NULL PRIMARY KEY, "errata_id" INTEGER NOT NULL, "cve_id" INTEGER NOT NULL, FOREIGN KEY ("errata_id") REFERENCES "errata" ("id"), FOREIGN KEY ("cve_id") REFERENCES "cve" ("id"));
CREATE INDEX "relationship_errata_id" ON "relationship" ("errata_id");
CREATE INDEX "relationship_cve_id" ON "relationship" ("cve_id");
CREATE UNIQUE INDEX "relationship_errata_id_cve_id" ON "relationship" ("errata_id", "cve_id");
Get a list of advisories for the last 2 days ( I need last day but today there was no advisory )
sqlite> SELECT * FROM errata WHERE releasedate > (SELECT DATETIME('now', '-2 day'));
id name severity releasedate
---------- -------------- ---------- --------------------
2722 RHSA-2017:0837 important 2017-03-23T00:21:00Z
2723 RHSA-2017:0838 moderate 2017-03-23T02:35:00Z
2724 RHSA-2017:0484 moderate 2017-03-23T04:59:00Z
2725 RHSA-2017:0494 moderate 2017-03-23T04:59:00Z
2726 RHSA-2017:0495 moderate 2017-03-23T05:04:00Z
2727 RHSA-2017:0486 moderate 2017-03-23T05:04:00Z
Get a list of ids associated with errata is '2722'
sqlite> select cve_id from relationship where errata_id='2722';
cve_id
----------
5002
5003
5004
5005
5006
5007
Get a list of cve names associated with errata name RHSA-2017:0837 ( errata id 5002 )
qlite> select * from cve where id='5002';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5002 CVE-2017-5208 important NULL 2017-01-08T00:00:00Z
sqlite> select * from cve where id='5003';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5003 CVE-2017-5332 moderate NULL 2017-01-10T00:00:00Z
sqlite> select * from cve where id='5004';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5004 CVE-2017-5333 important NULL 2017-01-10T00:00:00Z
sqlite> select * from cve where id='5005';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5005 CVE-2017-6009 important NULL 2017-02-16T00:00:00Z
sqlite> select * from cve where id='5006';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5006 CVE-2017-6010 moderate NULL 2017-02-16T00:00:00Z
sqlite> select * from cve where id='5007';
id name severity cvss_score publicdate
---------- ------------- ---------- ---------- --------------------
5007 CVE-2017-6011 moderate NULL 2017-02-16T00:00:00Z

Join the tables:
SELECT e.name, c.name, e.severity, e.releasedate
FROM errata e
JOIN relationship r ON e.id = r.errata_id
JOIN cve c ON c.id = r.cve_id
WHERE e.releasedate > DATETIME('now', '-2 day')

Related

Constraints about

What constraints are copied with table when we create table by using create table as select statement..?
I don't know about MySQL, but - as of Oracle - only the NOT NULL constraint. Even if there was a column designed as a primary key (which - implicitly - means that it can't be NULL), newly created table won't have that constraint.
For example:
SQL> create table test_1
2 (id number primary key,
3 name varchar2(20) not null);
Table created.
SQL> select constraint_name, constraint_Type from user_constraints where table_name = 'TEST_1';
CONSTRAINT_NAME C
-------------------- -
SYS_C009194 C --> "C"heck (NOT NULL) constraint
SYS_C009195 P --> "P"rimary key constraint
SQL> create table test_2 as select * from test_1;
Table created.
SQL> select constraint_name, constraint_Type from user_constraints where table_name = 'TEST_2';
CONSTRAINT_NAME C
-------------------- -
SYS_C009196 C --> that's the "C"heck - NOT NULL constraint
SQL> desc test_2
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME NOT NULL VARCHAR2(20)
SQL>
MySQL would only preserve NOT NULL as constarint
CREATE TABLE tab1(id int AUTO_INCREMENT PRIMARY KEY)
create table tab2
(id int primary key,
col1 varchar(20) not null,
col2 int UNIQUE,
col3 int, FOREIGN KEY (col3) REFERENCES tab1(id))
CREATE TABLE tab3 AS SELECT * FROM tab2
Records: 0 Duplicates: 0 Warnings: 0
SHOW CREATE TABLE tab3
Table
Create Table
tab3
CREATE TABLE `tab3` (  `id` int NOT NULL,  `col1` varchar(20) NOT NULL,  `col2` int DEFAULT NULL,  `col3` int DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
fiddle

Can you use a subquery in LPAD?

I have a list of 9 digit IDs in a table I called "numbers", with one column called "ID". I want to use those in a subquery to look for specific rows in a table called artransaction. The problem is that in the transactionid column in artransaction, it has a zero in front of the 9 digit ID.
So if I do:
select * from artransaction
where transactionid in lpad((select id from numbers where rownum=1),10,'0');
It comes back with a result. But if I do:
select * from artransaction
where transactionid in lpad((select id from numbers),10,'0');
It says "single-row subquery returns more than one row"
Is it possible to put in a subquery in LPAD?
You should rewrite that query. Here's an example based on Scott's EMP table - I want to select rows that contain COMM which looks like the ones stored in the NUMBERS table.
SQL> select ename, comm from emp order by ename;
ENAME COMM
---------- ----------
ALLEN 300
BLAKE
CLARK
FORD
JAMES
JONES
KING
MARTIN 1400
MILLER
SMITH
TURNER 0
WARD 500
12 rows selected.
SQL>
Sample NUMBERS table:
SQL> create table numbers (comm number);
Table created.
SQL> insert into numbers values (14);
1 row created.
SQL> insert into numbers values (50);
1 row created.
SQL> insert into numbers values (3);
1 row created.
SQL> select * From numbers;
COMM
----------
14
50
3
SQL>
Testing:
SQL> -- This one will work because of the ROWNUM = 1 condition, which returns a single value
SQL> select * from emp
2 where comm in rpad((select comm from numbers where rownum = 1), 4, '0');
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
7654 MARTIN SALESMAN 7698 28.09.1981 1250 1400 30
SQL> -- This will result in error because NUMBERS contain several values
SQL> select * from emp
2 where comm in rpad((select comm from numbers), 4, '0');
where comm in rpad((select comm from numbers), 4, '0')
*
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row
SQL> -- So - rewrite it
SQL> select * from emp
2 where comm in (select rpad(comm, 3, '0') from numbers);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
7521 WARD SALESMAN 7698 22.02.1981 1250 500 30
7499 ALLEN SALESMAN 7698 20.02.1981 1600 300 30
SQL>
Or, applied to your query:
select * from artransaction
where transactionid in (select lpad(id, 10, '0') from numbers);

How to use `NULL` in a `where` clause

In sqlite3 I am combining entries from various tables in a new table (making use ot primary and foreign key contsraints; for details see at the bottom):
select * from files;
id file description
---------- -------------- ----------------
1 testmodel1.dat first test model
2 testmodel2.dat second test mode
select * from patches;
id patch description
---------- ---------- ------------
1 testpatch test patch
Combined table:
select * from patched_files;
id files_id patches_id
---------- ---------- ----------
1 1 NULL
2 1 1
3 2 1
Some files do get patched some not (sometimes the same file).
I would like to retrieve this view from the database (expected result):
id file patch
---------- -------------- ----------
1 testmodel1.dat
2 testmodel1.dat testpatch
3 testmodel2.dat testpatch
I tried this:
select patched_files.id as id,patched_files.files_id as file_id, files.file as file, patched_files.patches_id as patch_id, patches.patch as patch
from patched_files, files, patches
where patched_files.files_id=files.id and patched_files.patches_id=patches.id;
id files_id file patches_id patch
---------- ---------- -------------- ---------- ----------
2 1 testmodel1.dat 1 testpatch
3 2 testmodel2.dat 1 testpatch
Here, I am missing the unpatched file (rowid 1) and I understand why.
So I added an or:
select patched_files.id as id,patched_files.files_id as file_id, files.file as file, patched_files.patches_id as patch_id, patches.patch as patch
from patched_files, files, patches
where patched_files.files_id=files.id and (patched_files.patches_id=patches.id or patched_files.patches_id is NULL);
id file_id file patch_id patch
---------- ---------- -------------- ---------- ----------
1 1 testmodel1.dat NULL testpatch
2 1 testmodel1.dat 1 testpatch
3 2 testmodel2.dat 1 testpatch
I understand why this is happening (composite table from "files" and "patches").
How can I avoid the patch name being stated if the patch_id is NULL?
Do I need to insert a "dummy" in the "patches" table?
Recreating the example:
-- original files:
create table files (id integer primary key, file text, description text);
insert into files (file, description) values('testmodel1.dat', 'first test model');
insert into files (file, description) values('testmodel2.dat', 'second test model');
-- patches:
create table patches (id integer primary key, patch text, description text);
insert into patches (patch, description) values('testpatch', 'test patch');
-- patched files (combination of files and patches):
create table patched_files (id integer primary key, files_id integer references files(id) on delete restrict deferrable initially deferred, patches_id integer references patches(id) on delete restrict deferrable initially deferred);
insert into patched_files (files_id) values(1);
insert into patched_files (files_id, patches_id) values(1,1);
insert into patched_files (files_id, patches_id) values(2,1);
You are looking for an outer join:
select f.id, f.file, p.patch, p.description
from files f
left join patched_files pf on pf.files_id = f.id
left join patches p on p.id = pf.patches_id
Online example: http://rextester.com/ZNMAY53081

Removing duplicate row from SQLite3

I have a SQLite3 DB with ~10,000 rows of data.
The schema is like this:
id, stock_id, body, stock_created_at, symbol, updated_at, created_at
The PK is id with no FK
You can tell there is a duplicate if the stock_id is duplicated.
I have a MySQL query like this that I used to use, but it's for MySQL and not SQLite:
DELETE FROM stocks WHERE id NOT IN
(SELECT MAX(id) FROM table GROUP BY stock_id);
Using SQLite3 (SQLite version 3.8.10.2 2015-05-20 18:17:19):
sqlite> create table test (id int, stock_id int, symbol text);
sqlite> insert into test values (1, 1, 'GOOG');
sqlite> insert into test values (2, 1, 'GOOGL');
sqlite> insert into test values (3, 2, 'AAPL');
sqlite> select * from test;
id stock_id symbol
---------- ---------- ----------
1 1 GOOG
2 1 GOOGL
3 2 AAPL
sqlite> delete from test
...> where id in (
...> select max(id) from test
...> group by stock_id
...> having count(*) > 1
...> );
sqlite> select * from test;
id stock_id symbol
---------- ---------- ----------
1 1 GOOG
3 2 AAPL
If stock table was a completely different table, the same concept works quite well:
sqlite> create table stock (stock_id int);
sqlite> insert into stock values (1);
sqlite> insert into stock values (2);
sqlite> insert into stock values (3);
sqlite> delete from stock
...> where stock_id in (
...> select max(id) from test
...> group by stock_id
...> having count(*) > 1
...> );
sqlite> select * from stock;
stock_id
----------
1
3
Does this kind of query work for you? If not, what SQLite version are you using and can you edit your question with example data?

Sqlite3 not matching rows with NULL values when using inclusion operator

For some reason, sqlite3 is not matching rows that have a NULL value for a query that clearly should match it.
Say I have an employees table with two columns name and salary that has the following data:
sqlite> SELECT * FROM employees;
id name salary
--------------- --------------- ---------------
1 John Smith 10000
2 Mary Anderson 20000
3 David White NULL
Executing the following query results in:
sqlite> SELECT * FROM employees WHERE salary NOT IN (10000);
id name salary
--------------- --------------- ---------------
2 Mary Anderson 20000
Shouldn't I also expect row with id=3 to be in the list? Why isn't it on the list? I've been able to confirm this behavior in sqlfiddle.
You can't compare NULL to anything. There are IS NULL and IS NOT NULL operators in SQL to deal with it.
The proper query would be
SELECT *
FROM employees
WHERE salary NOT IN(50000)
OR salary IS NULL;
Here is SQLFiddle demo

Resources