Table Name: free_meals_bill
punch_date employee_id employee_name product_name
2021-02-22 12:15:50.086471 123456 john Variety Rice - Curd - Rs.35
2021-02-22 12:19:50.086472 234456 marry Variety Rice - Curd - Rs.35
2021-02-22 12:22:50.086473 355456 peter Variety Rice - Curd - Rs.35
Before inserting into "free_meals_bill" table, I want to check that per employee_id only one punch is allowed.
For example, if john (employee id 123456) is already in the free_meals_bill then again for the same date, john data should not be insert again into the "free_meals_bill" table.
Query:
insert into free_meals_bill (punch_date,employee_id,employee_name,product_name)
Values ('2021-02-22 10:15:50.086471',123456,'john','Variety Rice - Curd - Rs.35')
SELECT
employee_id,
COUNT(*) as count,
date_trunc('day',punch_date) as day
FROM bill_item
WHERE punch_date>= CURRENT_DATE
GROUP BY employee_id, day
HAVING COUNT(*) = 0
You can use a NOT EXISTS condition to check if the to be inserted values already exist:
insert into free_meals_bill (punch_date, employee_id, employee_name, product_name)
select *
from (
values (date '2021-02-22 10:15:50.086471',123456,'john','Variety Rice - Curd - Rs.35')
) as t(punch_date, employee_id, employee_name, product_name
where not exists (SELECT *
FROM free_meals_bill bi
WHERE bi.punch_date::date = t.punch_date::date
AND bi.employee_id = t.employee_id)
But if you only allow one row per (employee_id, punch_date) you should create a unique constraint or index
create unique index only_one_meal_per_day
on free_meals_bills ( (punch_date::date), employee_id);
Then you can do:
insert into free_meals_bill (punch_date, employee_id, employee_name, product_name)
values (date '2021-02-22 10:15:50.086471',123456,'john','Variety Rice - Curd - Rs.35')
on conflict ((punch_date::date), employee_id)
do nothing;
Your select statement has wrong column sequence, it should be the same sequence with your insert statement. date,id,name,product. And, should be the same number of columns too.
demo:db<>fiddle
You cannot use VALUES and SELECT in one INSERT statement. The SELECT statement replaces the VALUES part
You can use EXISTS to check for occurrences.
INSERT INTO free_meals_bill (punch_date,employee_id,employee_name,product_name)
SELECT
*
FROM bill_item
WHERE punch_date >= CURRENT_DATE
AND NOT EXISTS (
SELECT 1 FROM free_meals_bill WHERE employee_id = bill_item.employee_id
);
Note: I used * selector here, because in my example bill_item has the same columns as free_meals_bill. You have to adapt this to your real used case, of course, if it doesn't fit to something like this (depending on how bill_item actually looks like):
SELECT
punch_date,
employee_id,
employee_name,
product_name
...
Edit:
To avoid such duplication by table design you should think about adding a UNIQUE contraint to your table:
ALTER TABLE free_meals_bill ADD CONSTRAINT my_unique_constraint UNIQUE (employee_id);
This prevents INSERT statements from inserting duplicate records automatically, you don't need to do this with SELECT statements
Related
I have Two tables that contain employees.
One table has all active employees (Current_Employees) and the other one has employees that have been joined in the last month (Greenhouse_Employees). Sometimes these employees overlap.
I have a unqiue ID (position_ID) that I want to do the following with in the abstract:
If Greenhouse_Employees unique ID exists in or matches to an ID in Current_Employees, ignore, if it does not: append it and its associated columns to the table
Not all of the columns match in either table, some do.
The code below almost works, but if there is a single inconsistency any any column I coalesce, it duplicates the row: (Some employees have inconsistent [loc] (locations) in the tables due to data entry error
SELECT
COALESCE(#CURRENT_EMPLOYEES.[employee_status], [GREENHOUSE_TABLE].[job_status]) AS employment_status
,COALESCE(#CURRENT_EMPLOYEES.[employee_id], 'N/A') AS employee_id
,COALESCE(#CURRENT_EMPLOYEES.[employee_name], CONCAT([GREENHOUSE_TABLE].[first_name],' ',[GREENHOUSE_TABLE].[last_name])) AS employee_name
,COALESCE(#CURRENT_EMPLOYEES.[hire_date], [GREENHOUSE_TABLE].[hire_date]) AS hire_date
,COALESCE(#CURRENT_EMPLOYEES.[salary], [GREENHOUSE_TABLE].[salary]) AS salary
,COALESCE(#CURRENT_EMPLOYEES.[bonus_percent], [GREENHOUSE_TABLE].[annual_bonus]) AS bonus_percent
,COALESCE(#CURRENT_EMPLOYEES.[commission_percent], '0') AS commission_percent
,COALESCE(#CURRENT_EMPLOYEES.[currency], 'N/A') AS currency
,COALESCE(#CURRENT_EMPLOYEES.[company_title], [GREENHOUSE_TABLE].[company_title]) AS company_title
,COALESCE(#CURRENT_EMPLOYEES.[company_department], [GREENHOUSE_TABLE].[company_department]) AS company_department
,COALESCE(#CURRENT_EMPLOYEES.[country], 'N/A') AS country
,COALESCE(#CURRENT_EMPLOYEES.[loc], 'N/A') AS loc
,COALESCE(#CURRENT_EMPLOYEES.[job_level], [GREENHOUSE_TABLE].[job_level]) AS job_level
,COALESCE(#CURRENT_EMPLOYEES.[kamsa_code], [GREENHOUSE_TABLE].[kamsa_code]) AS kamsa_code
,COALESCE(#CURRENT_EMPLOYEES.[position_id],[GREENHOUSE_TABLE].[position_id]) AS position_id
FROM #CURRENT_EMPLOYEES
FULL JOIN [Headcount].[dbo].[greenhouse_employees] AS GREENHOUSE_TABLE ON #CURRENT_EMPLOYEES.[position_id] = [GREENHOUSE_TABLE].[position_id]
ORDER BY #CURRENT_EMPLOYEES.[hire_date] ASC
I believe you need to You need to INSERT ... SELECT ... WHERE NOT EXISTS(...) or INSERT ... SELECT ... WHERE <Id> NOT IN (...). Something like:
INSERT #CURRENT_EMPLOYEES (employee_status, employee_id, ...)
SELECT employee_status, employee_id, ...
FROM Headcount.dbo.greenhouse_employees GE
WHERE NOT EXISTS (
SELECT *
FROM #CURRENT_EMPLOYEES CE
WHERE CE.employee_id = GE.employee_id
)
The other form is
INSERT #CURRENT_EMPLOYEES (employee_status, employee_id, ...)
SELECT employee_status, employee_id, ...
FROM Headcount.dbo.greenhouse_employees GE
WHERE GE.employee_id NOT IN (
SELECT CE.employee_id
FROM #CURRENT_EMPLOYEES CE
)
Both assume that employee_id is unique in greenhouse_employees.
Assume that there is an employee table and a project table.
A relationship table emp_proj contains following column: (id, emp_id, proj_id)
I would like to delete rows from emp_proj that contain following pairs of (emp_id, proj_id) : (1,101) , (1,102), (2,202), (3,303)
Note that the table may contain other rows with emp_ids 1, 2 and 3.
How would I use WHERE clause that would compare these pairs ?
I thought of using nesting of ORs but that would complicate the query.
Also I would like to do a bulk delete operation that in one-go, would delete all rows that contain the concerned pairs.
On Postgres, your suggested approach might be the only option:
DELETE
FROM emp_proj
WHERE
emp_id = 1 AND proj_id = 101 OR
emp_id = 1 AND proj_id = 102 OR
emp_id = 2 AND proj_id = 202 OR
emp_id = 3 AND proj_id = 303;
Note that on certain other databases, such as MySQL, you could have used a tuple syntax which is a bit more terse:
DELETE
FROM emp_proj
WHERE
(emp_id, proj_id) IN ((1, 101), (1, 102), (2, 202), (3, 303));
I have a reference table (in Postgres) and multiple other tables which can reference data in/from this table. It would make sense to use foreign keys to manage this, but I was wondering how one could manage updating the entries in the reference table in the best way when new values come in.
I guess it could be done through the coding that handles the data ingestion and check and insert new values in the reference and after that add the data to the other table. This doesn't seem ideal somehow to me, so I wondered what the best practice is in handling this situation. As there is management of deletion present in SQL I wondered if the opposite might also be available for instance? (not to prevent insertion, but sort of cascading of the values?)
Example reference table;
company_id - company_name
1 - test1
2 - test2
3 - test3
table with sales to companies:
company_id - month - year - sales
1 - January - 2020 - 10000
2 - January - 2020 - 8000
1 - December - 2019 - 9000
3 - November - 2019 - 7000
Now data can come in including rows like;
company_name - month - year - sales
test4 - January - 2020 - 10000
test5 - January - 2020 - 1000
Ideally I could insert this with one query and update the reference table with the new company name so that it gets an id that will be used in the sales table.
You can first check if the record in the reference table exists ..
SELECT
EXISTS(
SELECT TRUE FROM company
WHERE name = 'test2');
And in case it does you can insert the sales normally making reference to the company table. If it does not, you can use a CTE to insert the new company and get its id, so that you can outside the CTE insert the new sales record ..
WITH j AS (
INSERT INTO company (name)
VALUES ('test2')
RETURNING id
)
INSERT INTO sales (company_id, sales)
SELECT j.id, 42000 FROM j;
Testing script to add a new company
CREATE TABLE company (
id SERIAL PRIMARY KEY,
name TEXT);
INSERT INTO company (name) VALUES ('test1');
CREATE TABLE sales (
company_id INTEGER REFERENCES company(id),
sales NUMERIC);
WITH j AS (
INSERT INTO company (name)
VALUES ('test2')
RETURNING id
)
INSERT INTO sales (company_id, sales)
SELECT j.id, 42000 FROM j;
SELECT * FROM sales
JOIN company ON company.id = sales.company_id;
company_id | sales | id | name
------------+-------+----+-------
2 | 42000 | 2 | test2
(1 Zeile)
If you want to ignore records that violate the foreign key constraint, check this answer by #a_horse_with_no_name.
Edit: Using anonymous code blocks including checks and inserts
DO $$
BEGIN
IF EXISTS(SELECT TRUE FROM company WHERE name = 'test1') THEN
INSERT INTO sales (company_id, sales)
VALUES ((SELECT id FROM company WHERE name = 'test1'),42000);
ELSE
WITH j AS (
INSERT INTO company (name)
VALUES ('test1')
RETURNING id
)
INSERT INTO sales (company_id, sales)
SELECT j.id, 42000 FROM j;
END IF;
END$$;
Error Code Screenshot (ShipDate is now the error)
For my school project we are to create a product database where the customer places an order etc. I've compared my code to classmates and it's the essentially the same except I have less columns. This section of the code inserts the user input into the Orders Table.
The 2nd to last Column, OrderStatus, is where the * appears in the console. I apologize ahead of time if it looks messy, for some reason the format in the Body doesn't carry over to publish posts.
CODE:
INSERT INTO Orders
VALUES (OrderNum,
OrderDate,
CustID,
PNum,
UnitPrice,
QtyOrder,
TotalCost,
ShipDate,
QtyShipped,
OrderStatus,
NULL);
SELECT MaxNum,
SYSDATE,
&vCustID,
'&vPNum',
UnitPrice,
&vQty,
TotalCost,
ShipDate,
QtyShipped,
'Open',
Orders.ReasonNum
FROM CancelledOrder, Orders, Counter
WHERE Orders.ReasonNum = CancelledOrder.ReasonNum;
COMMIT;
Orders Table for reference
CREATE TABLE Orders
(
OrderNum NUMBER (4) PRIMARY KEY,
OrderDate DATE,
CustID CHAR (3),
PNum VARCHAR2 (3),
UnitPrice NUMBER,
QtyOrder NUMBER,
TotalCost NUMBER,
ShipDate DATE,
QtyShipped NUMBER,
OrderStatus VARCHAR2 (10),
ReasonNum NUMBER,
CONSTRAINT fk_CustID FOREIGN KEY (CustID) REFERENCES Customer (CustID),
CONSTRAINT fk_PNum FOREIGN KEY (PNum) REFERENCES Product (PNum),
CONSTRAINT fk_ReasonNum FOREIGN KEY
(ReasonNum)
REFERENCES CancelledOrder (ReasonNum)
);
I presume that INSERT should go along with SELECT, i.e.
insert into ...
select ... from
On your example:
INSERT INTO Orders (OrderNum, --> no VALUES keyword, but list of columns
OrderDate,
CustID,
PNum,
UnitPrice,
QtyOrder,
TotalCost,
ShipDate,
QtyShipped,
OrderStatus,
reasonnum) --> reasonnum instead of null
SELECT MaxNum,
SYSDATE,
&vCustID,
'&vPNum',
UnitPrice,
&vQty,
TotalCost,
ShipDate,
QtyShipped,
'Open',
Orders.ReasonNum
FROM CancelledOrder, Orders, Counter
WHERE Orders.ReasonNum = CancelledOrder.ReasonNum;
Also, check FROM & WHERE clauses: there are 3 tables involved with only one condition. You'll get - as a result - more rows than you expected, unless you fix that (or unless COUNTER table contains only 1 row).
For these examples, imagine two tables, a and b, with 3 columns each.
When you are inserting, the statement must either use:
Method A) Here we instruct the database to INSERT (to all or to specific columns) the results of a query. To do this, we write INSERT INTO SELECT ..... for example:
INSERT INTO table_a select table_b.* from table_b --Useful when we know how many columns table a and b have;
or
INSERT INTO table_a select b.column_2, b.column_3, b.column_1 from table_b --Usefull if b had more columns and we want those three, or if the order of the columns of b needs id different from the order of the columns of a
[In this case, all columns of table a will be filled with the respective columns from the rows of table b that the select part of the query returns]
or:
INSERT INTO table_a (tab_a_column1, tab_a_column3) select b.column_1, b.column_3 from table_b
[In this case, only the specified columns of table a will be filled with the columns from table b that the select part of the query returns]
-> Note that in these examples the VALUES keyword is never used
Method B) In this case we instruct the database to insert a sinlge new row with specific values into the table (to all or to specific columns of the table). In this method we do not use a select query at all:
INSERT INTO table_a VALUES ( 1, 'asdf', 5658 ) ;
In this example we just give some values to be inserted. They will be put in the corresponding columns of table_a, in the order that the columns are in the table.
INSERT INTO table_a (tab_a_column1, tab_a_column3) VALUES (1, 5658);
The numbers 1 and 5658 will be inserted to the first and third column, while the second one will be left NULL
So, when using VALUES, we are only inserting one row.
But when using Method A, our one statement may insert any number of rows at one go. It all will depend on how many rows the SELECT part of the query returns.
NOTE: the select part of the query in method A has no limit to how complex it can be. For example it can have multiple joins, where clauses, group by ... and more.
A good link that explains INSERT INTO can be found here:
https://www.techonthenet.com/sql/insert.php
I am new to SQL. Need a help from you guys :)
I am building a java appl and stuck in one of the scenario for insert with foreign key. Suppose I have 2 tables Employee_Type and Employee:
Table Employee_Type
| idType | position |
| -------- | -------------- |
| 1| Manager|
Table Employee
empId
EmpName
emp_type
FK (emp_type) reference Employee_type(idType)
Now values in Employee_Type
1,
Manager
I am inserting manually into Employee Table
INSERT INTO
employee (empId, name, emp_type)
VALUES
(
10, 'prashant', 1
)
Here in above insert I am inserting manually emp_type which is FK . My question, is there any way to insert FK value automatically using select like below example?
INSERT INTO
employee(empId, name, emp_type)
VALUES
(
10, 'prashant',
(
SELECT
idType
FROM
Employee_type,
employee
WHERE
employee.emp_type = employee_type.idtype
)
)
You don't specify your RDBMS and the syntax may therefore differ, but you should be able to restructure the statement to use literal values in an INSERT INTO ... SELECT format:
INSERT INTO employee (empId,name,emp_type)
SELECT
/* Build a SELECT statement which includes the static values as literals */
'10' AS empId,
'prashant' AS name,
/* and the idType column */
idType
FROM Employee_type,employee
WHERE employee.emp_type=employee_type.idtype
Note that without anything else in the WHERE clause, the above will insert one row into employee for every row matched by the SELECT statement.