sql insert statement to set rows proportional - java

I have a table with the following data (ofcourse there are many rows).
metric_id(int) | employee_id (string) | quota (double)
1 | abcd | 100
1 | wxyz | 120
What i want to do is a SQL INSERT that takes all values with a specific metric_id.
select * from mytable where metric_id=1;
Then use the results to create new entries with different metric_id that will have the quota value set at a specific proportion. (ie: metric_id=2 quota is 50% of metric_id=1)
So my end table after the insert would look like
metric_id(int) | employee_id (string) | quota (double)
1 | abcd | 100
1 | wxyz | 120
2 | abcd | 50
2 | wxyz | 60
Can this be done in one sql statement? I would like to use prepared statement to prevent inject if possible.

Try this. It should be what you need.
insert into some_table
(metric_id, employee_id, quota)
select
2, employee_id, quota * 0.5
from
some_table
where
metric_id = 1

More alternative way (no where clause needed):
INSERT INTO TableName
(metric_id,employee_id,quota)
SELECT metric_id+1,employee_id,quota/2
FROM TableName

Related

SQLException: UCAExc:::5.0.0 row column count mismatch

I have a project created by java code, and a database that has two tables (table1 and table2)
looks like this:
-------table1--------
Name | Ref
__________|__________
A | 100
B | 200
__________|__________
and
-------table2--------
Name | Q
__________|__________
A | 12
B | 10
A | 14
__________|__________
I try create a SQL query to get this result:
Name | Ref | SUM(Q)
__________|_________|__________
A | 100 | 26
B | 200 | 10
__________|_________|__________
I wrote this query
query ="SELECT table1.Name,table1.Ref FROM table1 WHERE table1.Name=(SELECT table2.Name,SUM(table2.Q) FROM table2 GROUP BY table2.Name)";
but my code not working and I'm getting this error:
net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::5.0.0 row column count mismatch
any suggestions to correct my query code?
Use this:
SELECT table1.Name,table1.Ref
FROM table1
WHERE table1.Name IN (SELECT table2.Name FROM table2)
Your subquery has two problems.
It returns more than one column, so it's not suitable for matching with = or IN.
It may return more than one row, so it's not suitable for matching with =.

How to set an a second Auto increment column per user?

I know this question has been asked before and most of the answers warn about doing so or suggest a solution for MyISAM but I'm using InnoDB.
I'm trying to generate an Invoice or Bill for the user for him to give out to me (Business plan requirement) !
The thing is that in my country the reference of the ID of the bill for the same person should be ordered or he will be audited for the missing bills. Like for example he gave me one bill with 0001 and the second one is 0005. He will be interrogated for the missing 4.
So I need to have a custom auto-increment per UserID.
User 1 - idUser= 1 ,idBill = 1
User 1 - idUser= 1 ,idBill = 2
User 2 - idUsr = 2 , idBill = 1
Some threads suggested using triggers while others warned about table locks. I personally not familiar with triggers so I steer away from them since they require maintenance.
I am using Java and MySQL.
An example:
CREATE TABLE main (id INT AUTO_INCREMENT PRIMARY KEY,
primary_id CHAR(3),
secondary_id INT) ENGINE = InnoDB;
CREATE TABLE auxiliary (primary_id CHAR(3),
secondary_id INT AUTO_INCREMENT,
PRIMARY KEY (primary_id, secondary_id)) ENGINE = MyISAM;
CREATE TRIGGER generate_secondary_id
BEFORE INSERT
ON main
FOR EACH ROW
BEGIN
INSERT INTO auxiliary (primary_id) VALUES (NEW.primary_id);
SET NEW.secondary_id = LAST_INSERT_ID();
END
INSERT INTO main (primary_id) VALUES
('A01'),
('A01'),
('B01'),
('C01'),
('A01'),
('B01'),
('A01'),
('B01');
SELECT * FROM main;
id | primary_id | secondary_id
-: | :--------- | -----------:
1 | A01 | 1
2 | A01 | 2
3 | B01 | 1
4 | C01 | 1
5 | A01 | 3
6 | B01 | 2
7 | A01 | 4
8 | B01 | 3
db<>fiddle here

Can I run an "explain analyze" on a query using JOOQ?

Can I run explain analyze on a query in JOOQ? like:
explain analyse select some, columns from some_table
but do it using JOOQ on PostgreSQL database?
I have found an interface org.jooq.Explain, with a method DSLContext.explain​(Query query) - but it seems just to use EXPLAIN on a query:
#Support({AURORA_MYSQL,AURORA_POSTGRES,H2,HSQLDB,MARIADB,MEMSQL,MYSQL,ORACLE,POSTGRES,SQLITE})
Explain explain​(Query query)
Run an EXPLAIN statement in the database to estimate the cardinality of the query.
Is there any sensible way to run an EXPLAIN ANALYZE on the database from the code side?
Yes you can run explain. Example
SelectWhereStep<ModuldefRecord> where = dsl.selectFrom(MODULDEF);
Explain explain = dsl().explain(where);
System.out.println(explain);
The output look like this (for Oracle)
+------------------------------------------------------------------------------+
|PLAN_TABLE_OUTPUT |
+------------------------------------------------------------------------------+
|Plan hash value: 3871168833 |
| |
|------------------------------------------------------------------------------|
|| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time ||
|------------------------------------------------------------------------------|
|| 0 | SELECT STATEMENT | | 61303 | 30M| 1305 (1)| 00:00:01 ||
|| 1 | TABLE ACCESS FULL| MODULDEF | 61303 | 30M| 1305 (1)| 00:00:01 ||
|------------------------------------------------------------------------------|
+------------------------------------------------------------------------------+
Explain also contains rows and cost
/**
* The number of rows (cardinality) that is estimated to be returned by the query.
* <p>
* This returns {#link Double#NaN} if rows could not be estimated.
*/
double rows();
/**
* The cost the database associated with the execution of the query.
* <p>
* This returns {#link Double#NaN} if cost could not be retrieved.
*/
double cost();
It's not supported yet: https://github.com/jOOQ/jOOQ/issues/10424. Use plain SQL templating, instead:
ctx.fetch("explain analyze {0}", select);
For mariadb I needed to do:
SelectConditionStep<TableNameRecord> select =
context.selectFrom(Tables.TABLE_NAME)
.where(filter);
System.out.println(context.fetch("analyze " + select.getSQL(ParamType.INLINED)));
which produced the output:
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+-------+--------+----------+------------------------+
| id|select_type|table |type |possible_keys |key |key_len|ref |rows|r_rows |filtered|r_filtered|Extra |
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+-------+--------+----------+------------------------+
| 1|SIMPLE |table_name|range|table_column_name|table_column_name|20 |{null}|1000|1000.00| 100.0| 100.0|Using where; Using index|
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+-------+--------+----------+------------------------+
If you use context.explain(select) as proposed by another answer you lose a few columns:
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+------------------------+
| id|select_type|table |type |possible_keys |key |key_len|ref |rows|Extra |
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+------------------------+
| 1|SIMPLE |table_name|range|table_column_name|table_column_name|20 |{null}|1000|Using where; Using index|
+----+-----------+----------+-----+-----------------+-----------------+-------+------+----+------------------------+

MySQL JSON column loses decimal precision when JSON object inserted as a string literal

I am trying to insert a JSON document into a MySQL JSON column and have noticed that decimal precision is lost in.
{"value": 212765.700000000010000}
Gets reduced to
{"value": 212765.7}
I've tried inserting directly via MySQL Workbench and I've noticed different behavior depending on how I do. For example:
insert into json_test values ('{"value": 212765.700000000010000}');
Produces the same result.. however the following works:
insert into json_test values (json_object('value', 212765.700000000010000));
I can generate the insert statement dynamically building the JSON object with the json_* function calls which works for single inserts.. but I'm using JDBC batch updates which requires the SQL to have a consistent number of parameters (our JSON documents vary in structure, so this does not work) or to explicitly set the values without using bind parameters which is obviously a security risk.
Any way around this?
As noted in the comments to the question, this appears to be an issue with the way MySQL parses JSON literals containing non-integer numeric values for which DOUBLE is not the best data type. If you want to supply the JSON as a string literal to speed up the batch insert process then one possible workaround would be to INSERT the numeric values as JSON strings and then UPDATE the rows after the batch insert is complete:
mysql> SELECT VERSION();
+-------------------------+
| VERSION() |
+-------------------------+
| 5.7.20-0ubuntu0.16.04.1 |
+-------------------------+
1 row in set (0.01 sec)
mysql> CREATE TABLE json_test (id INT PRIMARY KEY, jv JSON);
Query OK, 0 rows affected (0.20 sec)
Insert the numeric values as strings ...
mysql> INSERT INTO json_test (id, jv) VALUES (1, '{"value": "212765.700000000010000"}');
Query OK, 1 row affected (0.11 sec)
mysql> INSERT INTO json_test (id, jv) VALUES (2, '{"whatever": "foo"}');
Query OK, 1 row affected (0.06 sec)
mysql> INSERT INTO json_test (id, jv) VALUES (3, '{"value": "212765.700000000010000", "whatever": "bar"}');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM json_test;
+----+--------------------------------------------------------+
| id | jv |
+----+--------------------------------------------------------+
| 1 | {"value": "212765.700000000010000"} |
| 2 | {"whatever": "foo"} |
| 3 | {"value": "212765.700000000010000", "whatever": "bar"} |
+----+--------------------------------------------------------+
3 rows in set (0.01 sec)
... and then UPDATE the rows to CAST the values to DECIMAL:
mysql> UPDATE json_test SET jv = JSON_REPLACE(jv, '$.value', CAST(JSON_EXTRACT(jv, '$.value') AS DECIMAL(21,15))) WHERE JSON_TYPE(JSON_EXTRACT(jv, '$.value')) = 'STRING';
Query OK, 2 rows affected (0.04 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM json_test;
+----+------------------------------------------------------+
| id | jv |
+----+------------------------------------------------------+
| 1 | {"value": 212765.700000000010000} |
| 2 | {"whatever": "foo"} |
| 3 | {"value": 212765.700000000010000, "whatever": "bar"} |
+----+------------------------------------------------------+
3 rows in set (0.01 sec)
mysql> SELECT JSON_TYPE(JSON_EXTRACT(jv, '$.value')) AS jt FROM json_test WHERE id=1;
+---------+
| jt |
+---------+
| DECIMAL |
+---------+
1 row in set (0.01 sec)

Update stock table through the invoice table in MySQL

I have three tables which are customer, stock,invoice.
customer table PK is CNo(Customer No)
stock table PK is PNo(Product NO)
invoice table gets the both PKs(CNo from customer table and PNo from stock table) as Its Associate key .
What I want to do is , update stock table QuntyAvailable column through invoice table.
Ex. when a customer gets 2 Quantities from PNo 2 which is Dettol , it automatically update stock table QuntyAvailable column for above product's own row to 18( QuntyAvailable-Qty).
I tried many times with various queries but I got only errors. like PK cannot be Updated ..
bla bla bla......
Please help me on this Thank you.
customer table
CNo(PK) | Name | Address
1 | Jhon | 23, Hill St, NY.
2 | Sam | 24, Bejin , Chaina.
3 | Nic | 25, London ,England.
stock table
PNo(PK) | Description | Each Price | QntyAvailable
1 | Dettol | $2 | 10
2 | Astra | $5 | 20
invoice table
CNo(PK) | PNo(PK) | Qty | value
1 | 2 | 2 | $10
2 | 1 | 3 | $6
after the update done I want the stock table like this...
stock table
PNo(PK) | Description | Each Price | QntyAvailable
1 | Dettol | $2 | 7
2 | Astra | $5 | 18
Please help me .. I m using mysql server and netbeans IDE
My query -------------
s.executeUpdate("INSERT INTO invoice(CNo,PNo,Qty,Value) VALUES('1','2','10','150')"); s.executeUpdate("UPDATE stock set QuntyAvailable=QuntyAvailable-10 WHERE Pno ='2'");
If you want to update stocks table when you do an insert in invoice, you can either do the update after the insert with the data you have for the insert (like the one you tried, the only thing that looks wrong is the ='2' that looks like it should be only =2) or do it in a trigger, having the newly inserted values feed the update:
CREATE TRIGGER updateStock AFTER INSERT ON invoice
FOR EACH ROW BEGIN
UPDATE stock set QntyAvailable=QntyAvailable- new.Qty WHERE Pno =new.Pno;
END;
//
You can check this fiddle to see it working.
P.S.
You really should have an InvoiceID. The way you are constructing it, you are not allowing a customer to purchase the same product twice.
P.S. 2 - Your error creating the trigger is related to not setting the DELIMITER.
If you don't set it the statement will end at the first ; You need to set it before the trigger and end your trigger definition with it. After that you can set the delimiter back to ;.
DELIMITER //
CREATE TRIGGER updateStock AFTER INSERT ON invoice
FOR EACH ROW BEGIN
UPDATE stock set QntyAvailable=QntyAvailable- new.Qty WHERE Pno =new.Pno;
END;
//
DELIMITER ;

Categories