I have this table
CREATE TABLE "INGREDIENTS" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,
"material" VARCHAR,
"type" VARCHAR,
"company" VARCHAR
)
and I want to add a row
INSERT INTO "INGREDIENTS" VALUES('material1','type1','company1');
and I get an error, ... has 4 columns but 3 values supplied
However, I want the row to get the id value +1 from the previous row ..
You need to specify in which columns you insert
INSERT INTO INGREDIENTS (material, type, company)
VALUES ('material1', 'type1', 'company1');
You should actually always specify the columns. If you don't and your table changes then your queries will start to break.
Related
I wish to group data in a table and select the most up to date (last) non null field for each column. I was hoping to use window functions to partition the data, however, the window function yields one result per row in the window.
Consider the following example, there is a table which contains the rows personid and firstname and lastname. Updates to persons are stored by inserting a row with the same personid and non NULL values for the updated fields.
To retrieve the current state one has to select the last non NULL values for each column grouped by personid.
Here is my attempt:
Data:
CREATE TABLE IF NOT EXISTS "test" (
"id" INTEGER,
"firstname" TEXT,
"lastname" TEXT,
"personid" INTEGER,
PRIMARY KEY("id")
);
INSERT INTO "test" ("id","firstname","lastname","personid") VALUES (1,'Mark','Twain',1);
INSERT INTO "test" ("id","firstname","lastname","personid") VALUES (2,'Tom','hacksaw',2);
INSERT INTO "test" ("id","firstname","lastname","personid") VALUES (3,'Maximus',NULL,1);
Query:
SELECT * FROM
(SELECT
personid,
FIRST_VALUE(firstname) OVER (PARTITION BY personid ORDER BY firstname IS NULL, id DESC) AS firstname,
FIRST_VALUE(lastname) OVER (PARTITION BY personid ORDER BY lastname IS NULL, id DESC) AS lastname
FROM
test)
GROUP BY
personid
Note that I have to filter my result by pumping it through a GROUP BY, this makes me feel that the window function FIRST_VALUE is computed multiple times and feels inefficient. Is there a way to window data and get one result per group? (Since I have different orderings to filter out the null values for each respective column I do not see an efficient way using group by clauses)
Consider the following schema and table:
CREATE TABLE IF NOT EXISTS `names` (
`id` INTEGER,
`name` TEXT,
PRIMARY KEY(`id`)
);
INSERT INTO `names` VALUES (1,'zulu');
INSERT INTO `names` VALUES (2,'bene');
INSERT INTO `names` VALUES (3,'flip');
INSERT INTO `names` VALUES (4,'rossB');
INSERT INTO `names` VALUES (5,'albert');
INSERT INTO `names` VALUES (6,'zuse');
INSERT INTO `names` VALUES (7,'rossA');
INSERT INTO `names` VALUES (8,'juss');
I access this table with the following query:
SELECT *
FROM names
ORDER BY name
LIMIT 10
OFFSET 4;
Where offset 4 is used because it's the rowid (in the ordered list) to the first occurance of 'R%' names. This returns:
1="7" "rossA"
2="4" "rossB"
3="1" "zulu"
4="6" "zuse"
My question is, is there an SQL statement which can return the OFFSET value (in the R case above its 4) given a starting first letter please? (I don't really want to resort to stepping() through results, counting rows, until first 'R%' is reached!)
I've tried the following without success:
SELECT MIN(ROWID)
FROM
(
SELECT *
FROM names
ORDER BY name
)
WHERE name LIKE 'R%'
It always returns single row of NULL data.
As background, this table is a phone book list and I want to provide subset of results (from main table) back to caller, starting at a initial letter offset.
Just count the rows before the string of interest:
select count(*) from names where name < 'r';
The following has a number of options. Basically your issues is that the sub-query doesn't return the roiwd hencne NULL as the minimum. However, there is no need to use the rowid directly as the id column is an alias of the rowid, so that could be used:-
SELECT name, id, MIN(rowid), min(id) -- shows how rowid and id are the same
FROM
(
SELECT rowid, * -- returns rowid from the subquery so min(rowid) now works
FROM names
ORDER BY name
)
WHERE name LIKE 'R%' ORDER BY id ASC LIMIT 1 -- Will effectivley do the same (no need for the sub-query)
Extra columns added for demonstration.
As such your query could be :-
SELECT min(rowid) FROM names where name LIKE 'R%';
Or :-
SELECT min(id) FROM names where name LIKE 'R%';
You could also use :-
SELECT id FROM names WHERE name LIKE 'R%' ORDER BY id ASC LIMIT 1;
Or :-
SELECT rowid FROM names WHERE name LIKE 'R%' ORDER BY id ASC LIMIT 1;
I added a column in my SQLite database, and I need to insert repeating sequence numbers, starting with 1...n BUT it's based on grouping by other columns. The sequence needs to start over at 1 again when there is a new grouping.
Here is my table:
CREATE TABLE "ProdRunResults" ("ID" INTEGER PRIMARY KEY NOT NULL UNIQUE , "SeqNumbr" INTEGER, "Shift" INTEGER, "ShiftSeqNumbr" INTEGER, "Date" DATETIME, "ProdRunID" INTEGER, "Result" VARCHAR)
ShiftSeqNumbr is the new column that I need to populate with sequence numbers, based on grouping of numbers in ProdRunID column then by numbers in the Shift column.
There could be up to 3 "shifts" (work shifts in a 24 hr period).
I scraped together some code to do this but it adds the sequence numbers to ShiftSeqNumbr column in reverse (descending) order:
UPDATE ProdRunResults
SET ShiftSeqNumbr = (SELECT COUNT (*)
FROM ProdRunResults AS N
WHERE N.ProdRunID = ProdRunResults.ProdRunID
AND N.Shift = ProdRunResults.Shift
AND N.ShiftSeqNumbr = ProdRunResults.ShiftSeqNumbr);
How can I change the Update statement so the sequence numbers start at 1 and go up? Or is there a better way to do this?
Your UPDATE statement counts how many rows there are that have the same values in the ProdRunID/Shift/ShiftSeqNumbr columns as the current row. The current row always has an empty value in ShiftSeqNumbr, so it is counting how many rows in the current group have not yet been updated.
You need to count how many rows come before the current row, i.e., how many rows have the same ProdRunID and Shift values, and the same or a smaller SeqNumbr value:
UPDATE ProdRunResults
SET ShiftSeqNumbr = (SELECT COUNT (*)
FROM ProdRunResults AS N
WHERE N.ProdRunID = ProdRunResults.ProdRunID
AND N.Shift = ProdRunResults.Shift
AND N.SeqNumbr <= ProdRunResults.SeqNumbr);
Sqlite doesn't have a row number function. My database however could have several thousands of records. I need to sort a table based upon a date (the date field is actually an INTEGER) and then return a specific range of rows. So if I wanted all the rows from 600 to 800, I need to somehow create a row number and limit the results to fall within my desired range. I cannot use RowID or any auto-incremented ID field because all the data is inserted with random dates. The closest I can get is this:
CREATE TABLE Test (ID INTEGER, Name TEXT, DateRecorded INTEGER);
Insert Into Test (ID, Name, DateRecorded) Values (5,'fox', 400);
Insert Into Test (ID, Name, DateRecorded) Values (1,'rabbit', 100);
Insert Into Test (ID, Name, DateRecorded) Values (10,'ant', 800);
Insert Into Test (ID, Name, DateRecorded) Values (8,'deer', 300);
Insert Into Test (ID, Name, DateRecorded) Values (6,'bear', 200);
SELECT ID,
Name,
DateRecorded,
(SELECT COUNT(*)
FROM Test AS t2
WHERE t2.DateRecorded > t1.DateRecorded) AS RowNum
FROM Test AS t1
where RowNum > 2
ORDER BY DateRecorded Desc;
This will work except it's really ugly. The Select Count(*) will result in carrying out that Select statement for every row encountered. So if I have several thousands of rows, that will be a very poor performance.
This is what the LIMIT/OFFSET clauses are for:
SELECT *
FROM Test
ORDER BY DateRecorded DESC
LIMIT 200 OFFSET 600
I want to insert a new row in a table say 'table1' with autogenerated value for a single non-primary column with a formula condition max+1 i.e maximum value among elements of that particular column. Tell me the correct formula In shortHow to compute max value in a column of int type and then how to insert new row with max=1 value to that column
go to sql management studio ->rigth click on select table -> select design->then right click on your column->computed column specification->type desired formula hereORFetch max value from the database for desired column and then add max+1 to that value and insert it to that specific column(new row containing that computed value)
Insert Into table1
(autogeneratedcolumnname)
Values
((Select Max(value) + 1 From tablewithvaluecolumn))
Probably using OUTPUT clause you can achieve this..
INSERT INTO your_table('column1', 'column2')
OUTPUT inserted.column_to_compute
SELECT MAX(column_name) + 1 FROM your_table
Where column_to_compute is the name of column you want to hold computed values