I have two tables and A and B and i have a third table with result of join A and B,i use mariadb database, i want to store result in the third table result_A_B but I have this message when i run "CALL session_cpu_procedure()": ERROR 1136 (21S01): Column count doesn't match value count at row 1
CREATE TABLE result_A_B (
ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
cid nvarchar(100) NOT NULL,
time datetime NOT NULL,
OS nvarchar(100) NOT NULL,
program nvarchar(100) NOT NULL,
nb_OS_by_program FLOAT NOT NULL,
cpu FLOAT,
last_line int NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY (`cid`,`time`,`program`) ) ENGINE=InnoDB;
DELIMITER |
CREATE PROCEDURE session_cpu_procedure()
BEGIN
TRUNCATE result_session_cpu_CPLSVFX201P;
INSERT INTO result_session_cpu_CPLSVFX201P
SELECT DISTINCT C.cid, C.time, C.OS, C.program, COUNT(*) as nb_OS_by_program, O.cpu, C.last_line
FROM session_test C LEFT outer JOIN cpu_test O ON O.sid2 = C.cid and O.time = C.time and C.PROGRAM=O.MODULE
where C.time
GROUP BY C.time, C.OS, C.program, C.last_line;
END |
DELIMITER ;
CALL session_cpu_procedure();
I want to know how to resolve this error: ERROR 1136 (21S01): Column count doesn't match value count at row 1, thanks for any response
You have a table with 8 columns.
Your SELECT... INSERT statement has 7 columns.
This generated the rather self explanatory error.
Option 1:
Since you have a UNIQUE key already, make this the primary key and remove the AUTO_INCREMENT column.
Option 2:
Be explicit in your INSERT SELECT about the columns omitting the auto_increment column:
INSERT INTO result_session_cpu_CPLSVFX201P
(cid, time, OS, program, nb_OS_by_program, CPU, lastline)
SELECT ....
Related
I'm having some trouble trying to make a view with a calculated average column, for every movie row I need an average rating based on all the ratings for this movie in the rating table.
Movie table:
CREATE TABLE IF NOT EXISTS streaming_db.movie(
id BIGINT NOT NULL auto_increment
,name VARCHAR (100)
,description VARCHAR (1000)
,PRIMARY KEY (id)
) engine = InnoDB;
Rating table:
CREATE TABLE IF NOT EXISTS streaming_db.rating(
id BIGINT NOT NULL auto_increment
,rating_score DECIMAL(4, 2) NOT NULL
,comment VARCHAR (255) NULL
,id_profile BIGINT NOT NULL
,id_movie BIGINT NOT NULL
,PRIMARY KEY (id)
) engine = InnoDB;
Here's what I have so far:
CREATE VIEW streaming_db.midia
AS
SELECT name,
description
FROM streaming_db.movie a
INNER JOIN (SELECT avg(rating_score) AS averageRating from streaming_db.rating where
rating.id_movie = a.id);
It was telling me that a derived table needs its own alias, and I don't know if that really gives me the average per row.
You are attempting a correlated subquery in the FROM clause. Well, this is actually a real thing, called a lateral join.
But that is not your intention. Move the logic to the SELECT:
SELECT m.name, m.description,
(SELECT avg(rating_score)
FROM sistema_streaming_db.rating r
WHERE r.id_movie = m.id
) as averageRating
FROM streaming_db.movie m;
Note that I fixed the table aliases so they are abbreviations for the table names, which makes the query much easier to read.
I am trying to calculate the differential column of the score table upon inserting into a MySQL 8.0 database using a before trigger. The calculation uses the coursetee table as well. The trigger works fine on all but the first record in the table, which doesn't get updated. Is there something that I am missing? All relevant code is below.
CREATE TABLE coursetee (
teeID INT UNSIGNED AUTO_INCREMENT,
tee_name VARCHAR(20) NOT NULL,
course_rating DECIMAL(3,1) NOT NULL,
slope_rating INT UNSIGNED NOT NULL,
par INT UNSIGNED,
CONSTRAINT pk_coursetee PRIMARY KEY (teeID),
CREATE TABLE score (
roundID INT UNSIGNED AUTO_INCREMENT,
teeID INT UNSIGNED,
round_score INT UNSIGNED NOT NULL,
round_date DATETIME NOT NULL,
entry_date DATETIME DEFAULT NOW() NOT NULL,
differential DECIMAL(3,1),
CONSTRAINT pk_score PRIMARY KEY (roundID),
CONSTRAINT fk_score_coursetee FOREIGN KEY (teeID) REFERENCES coursetee(teeID));
DELIMITER $$
CREATE TRIGGER calculate_differential
BEFORE INSERT ON score
FOR EACH ROW
BEGIN
SET NEW.differential = (SELECT ROUND((113/ct.slope_rating)*(NEW.round_score-ct.course_rating),1)
FROM score, coursetee as ct
WHERE NEW.teeID = ct.teeID AND differential IS NULL);
END$$
DELIMITER ;
INSERT INTO coursetee
(courseID,tee_name,course_rating,slope_rating,par)
VALUES
(1,'Back',74.7,143,72),
(1,'Middle',72.6,136,72),
(1,'Front',71.3,132,72),
(2,'Back',76.8,155,72),
(2,'Middle',73.9,146,72),
(2,'Front',65.3,125,72);
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(1,2,79,'2019-07-25');
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(2,2,80,'2019-07-25');
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(1,2,77,'2019-08-06');
The query returns:
image of query not returning calculated record for row 1
CREATE TRIGGER calculate_differential
BEFORE INSERT
ON score
FOR EACH ROW
SET NEW.differential = ( SELECT ROUND((113/ct.slope_rating)*(NEW.round_score-ct.course_rating),1)
FROM coursetee ct
WHERE NEW.teeID = ct.teeID);
fiddle
The problem was in using score table as a source of the subquery. And the hope that differential BEFORE inserting the first record will give anything except NOT FOUND. And testing the field of the record BEFORE INSERT for NULL makes no sense.
My assumption is about the FROM clause of the differential query in the trigger. i'd suggest you to try change the order of the tables -
FROM score, coursetee as ct
to
FROM coursetee as ct, score
Seems like its trying to extract nothing for the first insert...
I'm trying to figure it out how to insert a row into a table on updating a particular field in the second table.
Let's say I have table 1 (dif):
CREATE TABLE dif
(
Position INT(10) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) UNSIGNED DEFAULT 0 NOT NULL
);
ALTER TABLE dif
ADD CONSTRAINT dif_article_pKey_fk
FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;
and table 2 (article):
CREATE TABLE IF NOT EXISTS article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
Number SMALLINT NOT NULL DEFAULT 0
PRIMARY KEY (pKey)
);
The table article is populated with some data and should be only updated. Table "dif" is empty at the beginning. So, let's say I'm updating the fields on "article" like this:
UPDATE article SET pKey = 15, Name = SomeName, Number = 22 WHERE pKey=15;
Can I somehow combine the UPDATE query with this?
INSERT INTO dif (pKey, Number) VALUES (15, 12);
The "12" is the difference between the "article.Number" before and after UPDATE.
No, but you can make a stored procedure that does both of those things and then execute it in a single statement.
create procedure GiveThisABetterName
(
in pKey int,
in newNumber int,
in currentNumber int,
in newName varchar(100)
)
begin
update
article
set
Name = newName, Number = newNumber
where
pKey = pKey;
insert into dif (pKey, Number) values (pKey, newNumber);
end
My mysql syntax is rusty, but that should be close. Then when you want to execute it:
call GiveThisABetterName(12, 15, 22, 'Some Name');
EDIT: After reading your question again, it seems to me that you're trying to make your data model track audit information that it's just not set up to accommodate naturally. Do you have control over the model? If so, consider something like this (see here for a working example of what's below):
CREATE TABLE IF NOT EXISTS article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
PRIMARY KEY (pKey)
);
CREATE TABLE ArticleNumbers
(
Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
Difference SMALLINT(3)
);
ALTER TABLE ArticleNumbers
ADD CONSTRAINT ArticleNumbers_article_pKey_fk
FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;
Maybe add a few views to make things easier:
CREATE VIEW GroupedArticleNumbers
as
select pKey, max(Counter) as Counter
from ArticleNumbers
group by pKey;
CREATE VIEW CurrentArticles
as
select article.pKey, article.Name, numbers.Number, numbers.Difference
from article
left outer join GroupedArticleNumbers filter on article.pKey = filter.pKey
left outer join ArticleNumbers numbers on filter.Counter = numbers.Counter;
Since you can track the number separately from the base record now but still easily determine what the current number is, you can now combine your update and insert statement functionality. See below.
First, some test data:
insert into article (Name) values ('Test');
insert into ArticleNumbers (pKey, Number, Difference) values (1, 10, null);
insert into ArticleNumbers (pKey, Number, Difference) select 1, 20, 20 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 50, 50 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 15, 15 - Number from CurrentArticles where pKey = 1;
See how nicely that works out once the overhead of setting up the schema has been done?
To get the current number for the article we created:
select * from currentarticles where pKey = 1
To get the number history for that article:
select * from article
left outer join articlenumbers on article.pkey = articlenumbers.pkey
order by counter asc
If you're willing to mess with your data model, you can have an alternative to stored procedures.
Alternatively, if you want to use triggers as #Jonathan Leffler suggested, something like this should work:
CREATE TABLE article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
PRIMARY KEY (pKey)
);
CREATE TABLE ArticleNumbers
(
Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
Difference SMALLINT(3)
);
delimiter $
create trigger tr_u_article
before update on article
for each row
begin
insert into ArticleNumbers (pKey, Number, Difference) select old.pKey, new.Number, new.Number - old.Number
end;
delimiter ;
Here are the two tables created:
CREATE TABLE category_tbl(
id int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
subcategory varchar(255) NOT NULL,
PRIMARY KEY(id),
CONSTRAINT nameSubcategory UNIQUE KEY(name, subcategory)
) ENGINE=InnoDB;
CREATE TABLE device(
id INT NOT NULL AUTO_INCREMENT,
cid INT DEFAULT NULL,
name VARCHAR(255) NOT NULL,
received DATE,
isbroken BOOLEAN,
PRIMARY KEY(id),
FOREIGN KEY(cid) REFERENCES category_tbl(id)
) ENGINE=InnoDB;
Below is the instruction that was given to me:
-- insert the following devices instances into the device table (you should use a subquery to set up foriegn keys referecnes, no hard coded numbers):
-- cid - reference to name: phone subcategory: maybe a tablet?
-- name - Samsung Atlas
-- received - 1/2/1970
-- isbroken - True
I'm getting errors on the insert statement below from attempting to use a sub-query within an insert statement. How would you solve this issue?
INSERT INTO devices(cid, name, received, isbroken)
VALUES((SELECT id FROM category_tbl WHERE subcategory = 'tablet') , 'Samsung Atlas', 1/2/1970, 'True');
You have different table name in CREATE TABLE and INSERT INTO so just choose one device or devices
When insert date format use the good one like DATE('1970-02-01')
When insert boolean - just TRUE with no qoutes I beleive.
http://sqlfiddle.com/#!9/b7180/1
INSERT INTO devices(cid, name, received, isbroken)
VALUES((SELECT id FROM category_tbl WHERE subcategory = 'tablet') , 'Samsung Atlas', DATE('1970-02-01'), TRUE);
It's not possible to use a SELECT in an INSERT ... VALUES ... statement. The key here is the VALUES keyword. (EDIT: It is actually possible, my bad.)
If you remove the VALUES keyword, you can use the INSERT ... SELECT ... form of the INSERT statement statement.
For example:
INSERT INTO mytable ( a, b, c) SELECT 'a','b','c'
In your case, you could run a query that returns the needed value of the foreign key column, e.g.
SELECT c.id
FROM category_tbl c
WHERE c.name = 'tablet'
ORDER BY c.id
LIMIT 1
If we add some literals in the SELECT list, like this...
SELECT c.id AS `cid`
, 'Samsung Atlas' AS `name`
, '1970-01-02' AS `received`
, 'True' AS `isBroken`
FROM category_tbl c
WHERE c.name = 'tablet'
ORDER BY c.id
LIMIT 1
That will return a "row" that we could insert. Just precede the SELECT with
INSERT INTO device (`cid`, `name`, `received`, `isbroken`)
NOTE: The expressions returned by the SELECT are "lined up" with the columns in the column list by position, not by name. The aliases assigned to the expressions in the SELECT list are arbitrary, they are basically ignored. They could be omitted, but I think having the aliases assigned makes it easier to understand when we run just the SELECT portion.
I am using INSERT ... SELECT to insert a data from specific columns from specific rows from a view into a table. Here's the target table:
CREATE TABLE IF NOT EXISTS `queue` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`customerId` int(11) NOT NULL,
`productId` int(11) NOT NULL,
`priority` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `customerId` (`customerId`),
KEY `productId` (`productId`),
KEY `priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
The INSERT ... SELECT SQL I have works, but I would like to improve it if possible, as follows: I would like the inserted rows to start with 1 in the priority column, and each subsequent row to increment the priority value by 1. So, if three rows were inserted, the first would be priority 1, the second 2, and the third 3.
A exception to the "start at 1" rule: if there are existing rows in the target table for the specified customer, I would like the inserted rows to start with MAX(priority)+1 for that customer.
I thought I could use a subquery, but here's the problem: sometimes the subquery returns NULL (when there are no records in the queue table for the specified customer), which breaks the insert, as the priority column does not allow nulls.
I tried to CAST the column to an integer, but that still gave me NULL back when there are no records with that customer ID in the table.
I've hardcoded the customer ID in this example, but naturally in my application that would be an input parameter.
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
(SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),
'queued',
null
FROM
`queue_eligible_products_view`
Is there a way to do this in one SQL statement, or a small number of SQL statements, i.e., less than SQL statement per row?
I do not think I can set the priority column to auto_increment, as this column is not necessarily unique, and the auto_increment attribute is used to generate a unique identity for new rows.
As Barmar mentions in the comments : use IFNULL to handle your sub query returning null. Hence:
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
IFNULL((SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),1),
'queued',
null
FROM
`queue_eligible_products_view`
Here's how to do the incrementing:
INSERT INTO queue (customerId, productId, priority, status, orderId)
SELECT 123, product_no, #priority := #priority + 1, 'queued', null
FROM queue_eligible_products_view
JOIN (SELECT #priority := IFNULL(MAX(priority), 0)
FROM queue
WHERE customerId = 123) var