I have 3 tables
works (id, name, date_started, date_finished, type_id, employer_id)
types (id, type)
employers (id, name, last_name, company)
I want when inserting into works table records in one query to insert into columns: name, date (by hand), then also into type_id and employer_id columns (selecting id from other tables)
I know you can insert and then use select, but how do i add the other values, that i need to type by hand as they dont exist on other tables?
You can just put the extra values directly in the SELECT clause:
INSERT INTO works (name, date_started, type_id, employer_id)
SELECT name, curdate(), type_id, employer_id
FROM types t
JOIN employers e ON ...
WHERE ...
You can have subqueries inside VALUES() clause, provided the subquery will only return one value.
INSERT INTO works (name, date_started, date_finished, type_id, employer_id)
VALUES
(
'name here',
'date started',
'date finished',
(SELECT id FROM types WHERE type = 'val' LIMIT 1),
(SELECT id FROM employers WHERE name = 'val' LIMIT 1)
)
Related
I'm trying to get all the items of the cart_items and add it to the ticket_items.
I've the error "SUBQUERY RETURN MULTIPLE ROWS", but that's what I want, insert all that rows in the ticket_items table in a same query.
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
VALUES (
(SELECT COUNT(ticket_id) FROM ticket),
(SELECT ISBN FROM cart_items WHERE customer_id = 1),
(SELECT quantity FROM cart_items WHERE customer_id = 1)
);
The issue is that you are using an aggregate function (COUNT) that will build exactly one value, but both isbn and quantity occur twice or more. So, the insert that will be built by your query is something like
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
VALUES (10, 1,2,3, 4,5,6);
This is of course not allowed. Since you do a COUNT, you need to apply GROUP BY to create multiple rows which will be inserted.
So your insert command will be something like this:
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
((SELECT COUNT(ticket_id), ISBN, quantity
FROM ticket, cart_items
WHERE customer_id = 1
GROUP BY ISBN, quantity));
This will work correctly and do what you asked for, I created an example here: db<>fiddle
You should check if this is really what you want because for me, it doesn't make sense to insert the count of ticket_id like you describe. But this is something you must check on your own.
Don't use VALUES keyword.
Please see syntax below:
INSERT INTO table2 (column1, column2, column3, ...)
SELECT column1, column2, column3, ...
FROM table1
WHERE condition;
I would first make sure that select gives you the expected result, then issue the insert statement.
Upon review, I believe the issue is with SELECT part.
You should rewrite it as one SELECT:
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
(SELECT
(SELECT COUNT(ticket_id) from ticket) as ticket_id, ISBN, quantity
FROM cart_items
WHERE customer_id = 1)
Good luck!
I want to insert many rows into two relative tables. I used LAST_INSERTED_ID() to insert data into the second table, but this id does not change
BEGIN;
insert into themes (tutorID, year, theme_name, degreeID)
select tutorID, year, work_name, degreeID from journal;
INSERT INTO assigned_students (studentID, tutorID, themeID, writing_language_id, work_typeID)
select studentID, tutorID, LAST_INSERT_ID(), 0, 4 from journal;
COMMIT
Give this a try, where you declare a INT and then set that value, see below.
BEGIN;
declare lastid INT;
insert into table1 (tutorID, year, name, degreeID)
select sm.tutorID, year, namework, dt.degreeID from table3;
set lastid = (SELECT LAST_INSERT_ID());
INSERT INTO table2 (studentID, tutorID, table1ID, writing_language_id, work_typeID)
select distinct StudentID, tutorID, lastid , 0, 4 from table3;
COMMIT;
You can also try this.
BEGIN;
insert into table1 (tutorID, year, name, degreeID)
select sm.tutorID, year, namework, dt.degreeID from table3;
INSERT INTO table2 (studentID, tutorID, table1ID, writing_language_id, work_typeID)
select distinct StudentID, tutorID, (SELECT LAST_INSERT_ID()), 0, 4 from table3;
COMMIT;
Make the inserts into assigned_students reference the just-inserted rows from themes (so you can get their auto generated IDs) also:
BEGIN;
insert into themes (tutorID, year, theme_name, degreeID)
select themeID, year, work_name, degreeID from journal;
INSERT INTO assigned_students (studentID, tutorID, themeID, writing_language_id, work_typeID)
select j.studentID, j.tutorID, t.THEME_ID_COLUMN_NAME, 0, 4
from
journal j
inner join themes t on j.themeID = t.tutorid;
COMMIT
Here we see that first we make some inserts into themes, and I presume it will autogenerate some IDs for themes' pk column.
So we then join journal onto those rows we inserted so we can retrieve the generated IDs
I don't know what the PK column of themes is called, so you'll have to replace THEME_ID_COLUMN_NAME with the correct value
Note that you might have to specify additional columns in on j.themeID = t.tutorid than just the tutorid, if that doesnt uniquely identify a row
I read also that for autoincrement columns it is guaranteed that the IDs are sequential, so you can get the LAST_INSERTED_ID() which is the mos trecently inserted row) as well as the ROW_COUNT and hence know the range of IDs that was inserted, and use that to select/join the journal data
I have the following table:
CREATE TABLE entries(
`id` INT UNSIGNED AUTO_INCREMENT,
`level` INT UNSIGNED,
`type` CHAR(2),
`attribute` INT UNSIGNED,
PRIMARY KEY(id)
);
From this table, I'm currently doing the same query for 3 different columns:
SELECT level, COUNT(*) FROM entries GROUP BY level;
SELECT type, COUNT(*) FROM entries GROUP BY type;
SELECT attribute, COUNT(*) FROM entries GROUP BY attribute;
I know I can use GROUP_CONCAT to get the DISTINCT entries for each of these in a single SQL call:
SELECT GROUP_CONCAT(DISTINCT level) AS levels, GROUP_CONCAT(DISTINCT type) AS types, GROUP_CONCAT(attribute) AS attributes FROM entries;
But can I manipulate this query to include the counts? OR is there a different way that I can get the distinct values and counts for these columns in a single call?
EDIT: here's some data to add to the table
INSERT INTO entries (level, type, attribute) VALUES (1, 'VA', 5), (1, 'CD', NULL), (NULL, 'VA', 3), (NULL, 'CD', NULL), (1, 'VA', 1);
And the sample output
LEVELS LEVEL_COUNTS TYPES TYPES_COUNTS ATTRIBUTES ATTRIBUTES_COUNTS
1 3 VA,CD 3,2 5,3,1 1,1,1
You can use the below query. The only things remaining are to add some column aliases, and to maybe add a condition to ignore rows where there is NULL.
SELECT *
FROM
(SELECT GROUP_CONCAT(lvlCount.level) as LEVELS,
GROUP_CONCAT(lvlCount.cnt) as LEVELS_COUNTS
FROM
(SELECT LEVEL,
COUNT(*) AS cnt
FROM entries where NOT(LEVEL IS NULL)
GROUP BY LEVEL
ORDER BY LEVEL DESC) AS lvlCount) AS LEVEL,
(SELECT GROUP_CONCAT(typeCount.type) as TYPES,
GROUP_CONCAT(typeCount.cnt) as TYPES_COUNTS
FROM
(SELECT TYPE,
COUNT(*) AS cnt
FROM entries where NOT(TYPE IS NULL)
GROUP BY TYPE
ORDER BY TYPE DESC) AS typeCount) AS TYPE,
(SELECT GROUP_CONCAT(attrCount.attribute) as ATTRIBUTES,
GROUP_CONCAT(attrCount.cnt) as ATTRIBUTES_COUNTS
FROM
(SELECT attribute,
COUNT(*) AS cnt
FROM entries where NOT(attribute IS NULL)
GROUP BY attribute
ORDER BY attribute DESC) AS attrCount) AS attribute;
SQLFiddle: http://sqlfiddle.com/#!2/4ea92/44
I have two tables:
purchase_mis(id, user_id, total_purchased, date)
daily_purchase(id, user_id, product_id, paid_amount, purchase_date)
I have a CRON file that runs every night, it counts the daily purchase from the "daily_purchase" table and runs insert into "purchase_mis".
For example:
SELECT
COUNT(*) AS purchase_count,
purchase_date
FROM daily_purchase
GROUP BY user_id;
This returns the purchase_count for every user and then it will be inserted to the "purchase_mis" table.
INSERT INTO
purchase_mis(user_id, total_purchased, date)
VALUES
('2', 'purchase_count', 'purchase_date');
But before inserting, it needs to check if the purchased information of user_id = 2 for some date "purchase_date" has already been inserted so it should not be inserted again.
I want something like the below query:
INSERT INTO
purchase_mis(user_id, total_purchased, date)
VALUES
('2', 'purchase_count', 'purchase_date')
WHERE date NOT EXISTS (SELECT date FROM purchase_mis WHERE user_id = '2');
Create a key on the date column, and then use INSERT IGNORE or INSERT ... ON DUPLICATE KEY UPDATE syntax. See this for more: "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
Also, you can probably use triggers or procedures instead of a cron job; might make life a bit easier.
insert into purchase_mis
(user_id, total_purchased, date)
select *
from (
select 2 as id,
100 as user_id,
str_to_date('2012-12-04', '%Y-%m-%d') as purchase_date
) t
where not exists (SELECT 1
FROM purchase_mis pm
WHERE pm.user_id = t.id
and pm.date = t.purchase_date);
I want to count the number of occurences of several substrings from the same column and with the same WHERE condition. For each substring I have a UNION SELECT statement including the repeating WHERE condition. The final result is a query with appox. 2500 lines of sql code, but it gives good result.
Simplified example of query:
SELECT ‘be’ AS country, count(destination) FROM demo
WHERE destination LIKE ‘%be%’ AND field_a=xzx AND field_b=bbb
UNION SELECT ‘de’ AS country, count(destination) FROM demo
WHERE destination LIKE ‘%de%’ AND field_a=xzx AND field_b=bbb
UNION SELECT ‘fr’ AS country, count(destination) FROM demo
WHERE destination LIKE ‘%fr%’ AND field_a=xzx AND field_b=bbb
UNION SELECT ‘nl’ AS country, count(destination) FROM demo
WHERE destination LIKE ‘%nl%’ AND field_a=xzx AND field_b=bbb
Is it possible to modify the query in such a way that the WHERE condition only appears once in the query?
Please find a simplified example of my question via this link:
https://docs.google.com/document/d/1otjZZlBy6au5E2I7T6NdSYmLayhNGWyXGxGo3gBx_-w/edit
DON'T store comma separated values in a single field. Instead, use a many:many relationship table and store one (id,country) combination per row. Your data structure is a SQL-Anti-Pattern and goes against all relational database design principles.
CREATE TABLE map (
demo_id INT,
country VARCHAR(2),
PRIMARY KEY (demo_id, country)
)
INSERT INTO map VALUES
(1, 'nl'), (1, 'de'), (1, 'be'), (1, 'fr'),
(2, 'de'), (2, 'fr'), (2, 'be'),
(3, 'fr'), (3, 'nl'),
(4, 'nl')
Then you will have this single query...
SELECT
map.country,
COUNT(*)
FROM
demo
INNER JOIN
map
ON map.demo_id = demo.id
WHERE
demo.field_a = 'xzx'
AND demo.field_b = 'bbb'
select a.country,count(*) from
(
select 'be' as country
union all
select 'de' as country
union all
select 'fr' as country
union all
select 'nl' as country
)a join demo d
on d.destination like '%'+a.country+'%'
AND d.field_a=xzx AND d.field_b=bbb
group by a.country
I am not sure whether mySQL supports derived table or not . If its not supported the you have to create a temp table with all different country values and replace it with table a in the above query
Use COUNT CASE WHEN ... THEN ... END
SELECT
COUNT(CASE WHEN destination LIKE "%be%" THEN 1 ELSE NULL END) AS "BE",
COUNT(CASE WHEN destination LIKE "%fr%" THEN 1 ELSE NULL END) AS "FR",
COUNT(CASE WHEN destination LIKE "%de%" THEN 1 ELSE NULL END) AS "DE",
COUNT(CASE WHEN destination LIKE "%nl%" THEN 1 ELSE NULL END) AS "NL"
FROM demo
WHERE field_a = "xzx" AND field_b = "bbb"
But you should really think about changing the structure of your table. Having comma-separated values in a single field is not really recommanded.
Instead, you should have for example here an ID for each travel (or whatever it is, I said travel because of the destination field). Then, make an entry for each destination within this travel. With this kind of structure, you'd have a request like this :
SELECT destination, COUNT(id)
FROM demo
WHERE field_a = "xzx" AND field_b = "bbb"
GROUP BY destination