PostgresSQL query for matching a subset on a column - database

I have a table looks like this:
EventID | Status
--------+------------
1 | Starting
1 | Processing
1 | Ended
2 | Starting
2 | Processing
3 | Starting
How can I write a query to get the EventId that is not yet 'Ended'? return like:
EventID
2
3
thanks.

The trick here is to use subqueries. You want a subquery of eventid values that you want to filter out of the main query. In other words, you don't want select eventid from events where status='Ended'. And you will link this subquery to your main query using the not in keyword.
First let's load some sample data.
create table events(EventID numeric, Status varchar);
insert into events values(1, 'Starting');
insert into events values(1, 'Processing');
insert into events values(1, 'Ended');
insert into events values(2, 'Starting');
insert into events values(2, 'Processing');
insert into events values(3, 'Starting');
commit
select * from events;
eventid | status
---------+------------
1 | Starting
1 | Processing
1 | Ended
2 | Starting
2 | Processing
3 | Starting
(6 rows)
And here is your desired query with the subquery filter.
select eventid from events where eventid not in (select eventid from events where status='Ended');
eventid
2
2
3
(3 rows)

Related

In SQL I have created a temporary table in that I want to insert multiple data into a single row with comma separated

CREATE TABLE #Tempdata
(
Account_Id varchar (max)
)
INSERT INTO #Tempdata
VALUES ('3', '4', '5');
I want data to be in single as shown in above.
What you want to do is:
Create #Tempdata(Account_Id varchar (max))
Insert into #Tempdata(Account_Id) values ('3,4,5');
Which would produce the following result;
| Account_Id |
| :--------: |
| 3,4,5 |
Your example would result into inserting multiple columns
example if you had created your table like so:
Create table #Tempdata(column1 varchar (max), column2 varchar
(max),column3 varchar (max))
Insert into #Tempdata(column1,column2,column3) values
('3','4','5');
then your query would the following result:
| column1 | column2 | column3 |
| ------- | ------- | ------- |
| 1 | 2 | 3 |
In this code, you're going to get a table set(multiple rows):
SELECT value
FROM #Tempdata
CROSS APPLY STRING_SPLIT(Account_Id, ',');
If you want column-oriented, I mean one row and multiple columns per value, you should apply pivot on the result of the previous query.

I am trying to create trigger to calculate sum of products but it is showing me compilation error

create or replace trigger total_amt
2 after insert or delete or update
3 on products
4 for each row
5 BEGIN
6 update products
7 SET products.total_prod_amt=(SELECT SUM(products.prod_price) FROM products
8 WHERE products.prod_id=products.prod_id
9 END;
10 /
Warning: Trigger created with compilation errors.
i am trying this code is it correct. i have to calculate sum of price of all products in my table.
I've added ); to end the sub-query and the SQL query. The trigger now compiles correctly.
Oracle is now giving different errors because the trigger is trying to modify a table which is mutating.
create table products(
prod_id int primary key,
prod_price int not null,
total_prod_amt int );
✓
create or replace trigger total_amt
after insert or delete or update
on products
for each row
BEGIN
update products
SET products.total_prod_amt=
(SELECT SUM(products.prod_price)
FROM products
WHERE products.prod_id=products.prod_id
);
END;
/
✓
select * from user_errors;
NAME | TYPE | SEQUENCE | LINE | POSITION | TEXT | ATTRIBUTE | MESSAGE_NUMBER
:--- | :--- | -------: | ---: | -------: | :--- | :-------- | -------------:
insert into products(prod_id, prod_price) values (1,10);
ORA-04091: table FIDDLE_DRLOPQIBFWCYUAPCXKVV.PRODUCTS is mutating, trigger/function may not see it
ORA-06512: at "FIDDLE_DRLOPQIBFWCYUAPCXKVV.TOTAL_AMT", line 2
ORA-04088: error during execution of trigger 'FIDDLE_DRLOPQIBFWCYUAPCXKVV.TOTAL_AMT'
db<>fiddle here

Returning the dynamic array overlap value in aggregate

I'm trying to figure out if there is a way to return the dynamic array overlap value in aggregate? The database I am using is PostgreSQL 13. Let me paint the picture...
The Test Table
CREATE TABLE test (
id BIGSERIAL,
group_id bigint NOT NULL,
groups bigint[] NOT NULL,
PRIMARY KEY (id)
);
The Test Data
INSERT INTO test (group_id, groups)
VALUES
(1, '{123, 321}'), (1, '{321, 123}'),
(2, '{999, 111}'), (2, '{111, 999}');
The Current Aggregate Query
SELECT
group_id, MAX(groups)
FROM
test
WHERE
groups && ARRAY[999, 123]::bigint[] GROUP BY group_id;
The Current Aggregate Query Result
| group_id | groups |
|----------|------------|
| 1 | {321, 123} |
| 2 | {999, 111} |
My Desired Aggregate Query Result
| group_id | groups | overlapped_at |
|----------|------------|---------------|
| 1 | {321, 123} | 123 |
| 2 | {999, 111} | 999 |
I want to to know which integer caused the overlap in a single query or transaction. Any ideas?
The solution I came up with was to use a custom function. This works for me as my groups are never more than two ints/bigints. If the groups were bigger I could see a more robust answer needed.
CREATE FUNCTION intersects(anyarray, anyarray)
RETURNS bigint
language sql
as $FUNCTION$
SELECT (ARRAY(
SELECT UNNEST($1)
INTERSECT
SELECT UNNEST($2)
)::bigint[])[1]::bigint;
$FUNCTION$;

How to INSERT rows based on other rows?

I need to run a query that will INSERT new rows into a SQL Server join table.
Suppose I have the following tables to describe which products a store sells and in which states:
products:
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 1 | Laptop |
| 2 | Aspirin |
| 3 | Mattress |
+------------+--------------+
stores:
+----------+------------+
| store_id | store_name |
+----------+------------+
| 1 | Walmart |
| 2 | Best Buy |
| 3 | Sam's Club |
+----------+------------+
products_stores_states:
+------------+----------+-------+
| product_id | store_id | state |
+------------+----------+-------+
| 1 | 2 | AL |
| 1 | 2 | AR |
| 2 | 2 | AL |
| 2 | 2 | AR |
| 3 | 2 | AL |
| 3 | 2 | AR |
+------------+----------+-------+
So here we see that Best Buy sells all 3 products in AL and AR.
What I need to do is somehow insert rows into the products_stores_states table to add AZ for all products it currently sells.
With a small dataset, I could do this manually, row by row:
INSERT INTO products_stores_states (product_id, store_id, state) VALUES
(1,2,'AZ'),
(2,2,'AZ'),
(3,2,'AZ');
Since this is a large dataset, this is not really an option.
How would I go about inserting a new state for Best Buy for every product_id that the products_stores_states table already contains for Best Buy?
Bonus: If a query could be made to do this for multiple states that the same time, that would be even better.
Right now, I cannot wrap my head around how to do this, but I assume there would need to be a subquery to get the list of matching product_id values I need to use.
The following query will do what you want to do
DECLARE #temp TABLE (
state VARCHAR(20)
)
-- we are inserting state names into a temp table to use it further
INSERT INTO #temp (state)
VALUES
('AZ'),
('MA'),
('TX');
INSERT INTO products_stores_states(product_id, store_id, state )
SELECT
T.product_id,
T.store_id,
temp.state
FROM(
SELECT DISTINCT
Product_id, store_id
FROM
products_stores_states
WHERE store_id = 2 -- the store_id for which you want to make changes
) AS T
CROSS JOIN
#temp AS temp
At first, we are storing the state names into a table variable. Then we need to select only the distinct store_id and product_id combinations for a specific store.
Then we should insert the distinct values cross join with the table variable where we stored state names.
Here is the live demo.
Hope, this helps! Thanks.
If you are positive the inserted state is "NEW" to the table, something like this would work, changing the state variable to whatever you want to insert the new records.
DECLARE #State CHAR(2), #StoreId INT;
SET #State = 'AZ';
SET #StoreId = 2;
INSERT INTO products_stores_states (product_id, store_id, state)
SELECT DISTINCT product_id, #StoreId, #State
FROM dbo.products_stores_states
WHERE store_id = #StoreId;
You could first see what this statement would add using this:
DECLARE #State CHAR(2)
SET #State = 'AZ';
SET #StoreId = 2;
SELECT DISTINCT product_id, #StoreId, #State
FROM dbo.products_stores_states
WHERE store_id = #StoreId;

Troubleshooting to implement SQL Server trigger

I have this table called InspectionsReview:
CREATE TABLE InspectionsReview
(
ID int NOT NULL AUTO_INCREMENT,
InspectionItemId int,
SiteId int,
ObjectId int,
DateReview DATETIME,
PRIMARY KEY (ID)
);
Here how the table looks:
+----+------------------+--------+-----------+--------------+
| ID | InspectionItemId | SiteId | ObjectId | DateReview |
+----+------------------+--------+-----------+--------------+
| 1 | 3 | 3 | 3045 | 20-05-2016 |
| 2 | 5 | 45 | 3025 | 01-03-2016 |
| 3 | 4 | 63 | 3098 | 05-05-2016 |
| 4 | 5 | 5 | 3041 | 03-04-2016 |
| 5 | 3 | 97 | 3092 | 22-02-2016 |
| 6 | 1 | 22 | 3086 | 24-11-2016 |
| 7 | 9 | 24 | 3085 | 15-12-2016 |
+----+------------------+--------+-----------+--------------+
I need to write trigger that checks before the new row is inserted to the table if the table already has row with columns values 'ObjectId' and 'DateReview' that equal to the columns values of the row that have to be inserted, if it's equal I need to get the ID of the exited row and to put to trigger variable called duplicate .
For example, if new row that has to be inserted is:
INSERT INTO InspectionsReview (InspectionItemId, SiteId, ObjectId, DateReview)]
VALUES (4, 63, 3098, '05-05-2016');
The duplicate variable in SQL Server trigger must be equal to 3.
Because the row in InspectionsReview table were ID = 3 has ObjectId and DateReview values the same as in new row that have to be inserted. How can I implement this?
With the extra assumption that you want to log all the duplicate to a different table, then my solution would be to create an AFTER trigger that would check for the duplicate and insert it into your logging table.
Of course, whether this is the solution depends on whether my extra assumption is valid.
Here is my logging table.
CREATE TABLE dbo.InspectionsReviewLog (
ID int
, ObjectID int
, DateReview DATETIME
, duplicate int
);
Here is the trigger (pretty straightforward with the extra assumption)
CREATE TRIGGER tr_InspectionsReview
ON dbo.InspectionsReview
AFTER INSERT
AS
BEGIN
DECLARE #tableVar TABLE(
ID int
, ObjectID int
, DateReview DATETIME
);
INSERT INTO #tableVar (ID, ObjectID, DateReview)
SELECT DISTINCT inserted.ID, inserted.ObjectID, inserted.DateReview
FROM inserted
JOIN dbo.InspectionsReview ir ON inserted.ObjectID=ir.ObjectID AND inserted.DateReview=ir.DateReview AND inserted.ID <> ir.ID;
INSERT INTO dbo.InspectionsReviewLog (ID, ObjectID, DateReview, duplicate)
SELECT ID, ObjectID, DateReview, 3
FROM
#tableVar;
END;

Resources