get the count for different data in single column as set - sql

I am having table "Activation" with the columns account ID and email and product name
product name column is having data like this below
Platform
Access
Onboard
OnGuard
Platform
Access
Onboard
OnGuard
when user activated we will insert the data as a set like this ( Platform
,Access
,Onboard
,OnGuard)
and i need to give a warning to the user if he is inserting more than one set (Platform,Access,Onboard,OnGuard)
I can get the count for single product name insertion like (platform or access), but i need to get the count for single set insertion here ..
Could any one please help on this query how to get count for single set insertion and i am using sql server as a DB for these insertions.
Many thanks in advance..
UPDATE
sorry for confusion i need to give a warning to user if he inserted more than one time any of the product name defined in the set not as a single set ..

Assuming that unique products count is 4, you can check it using aggregation along with having.
select accountid
from activation
group by accountid
having count(distinct productname) = 4
Or you can reverse the logic according to your need(if you want to get the users against whom not all products are defined by changing = to <>
DEMO

You Can Use this In Trigger.
DECLARE #Product_Name NVARCHAR(50)
IF EXISTS (SELECT 1
FROM Activation WHERE productname = #Product_Name) BEGIN
RAISERROR ('Product Name Already Exists', 16, 1)
END

Related

Oracle : Create session sequence?

I have a table as follows
The table contains my application users and stores their clients. The column User Client ID refers to a foreign key linked to a different table that stores the clients details.
I need another column (User Client Counter) which is a just a counter of the clients of each user. I need it to start from 1 and goes up for each individual application user.
For the moment I'm populating this by counting the number of clients for each user + 1 before inserting a new row in the table :
select count(*) + 1 into MyVariable from Mytable where UserClientId = Something
Then I use MyVariable in the column User Client Counter
This methods works quite well, but in case the user is connected from two different sessions, the query may produce a wrong number of counts... in addition to that the performance may be bad in case of big tables...
Is there anyway better way to replace such process by using sequences ?
I've been looking to session sequences but there are reset after the end of each session.
(This column is a business need and cannot be replaced by something like rownumber in restitution queries. Since every client has to keep always the same identifier for the application user)
Thank you in advance.
Cheers,
I think you can just create a unique index on the app user and the running number:
create unique index idx on mytable (app_user_id, num);
And then insert with max + 1:
insert into mytable (app_user_id, client_id, num)
values
(
:app_user_id,
:client_id,
coalesce((select max(num) + 1 from mytable where app_user_id = :app_user_id), 1)
);
For this sort of requirement to be safe you will need to be able to lock rows at the right level so that you don't have two sessions that think the they are allowed to use the same value. The impact of this is that while one session is inserting a row for the 'Company X' user, another session will wait for the first user to commit if they're also trying to insert a row for 'Company X'.
This is super easy when you just have a table that stores information at the right level.
You can have a table of your users with a counter column which starts at 0.
MY_APPLICATION_USER CLIENT_COUNTER
-------------------------------------------------- --------------
Company X 1
Company Y 3
Company Z 1
As you insert rows into your main table, you update this table first setting the client_counter to be client_counter + 1 (you do this as one insert statement, no risky select then update!), then you return the updated value into your value for the client_id. This can all be done with a simple trigger.
create or replace trigger app_clients_ins
before insert
on app_clients
for each row
declare
begin
update app_users
set client_counter = client_counter + 1
where my_application_user = :new.my_application_user
return client_counter into :new.user_client_number;
end;
/
Of course, like any sequence if you delete a row it's not going to allow your next insert to fill that gap.
(db<>fiddle https://dbfiddle.uk/?rdbms=oracle_18&fiddle=7f1b4f4b6316d5983b921cae7b89317a )
if you want to have unique values to be inserted and there are chances that multiple users can insert rows into the same table at the same time then it is better to user Oracle Sequence.
CREATE SEQUENCE id_seq INCREMENT BY 1;
INSERT INTO Mytable(id) VALUES (id_seq.nextval);
In you case I think you want different sequence created for each Customer, How many different Customers you have, if you have in 100's then i don't think create sequence will work as you may have to create as many sequence .

This Oracle SQL doesn't work in Oracle Apex

if :p6_internal_id is null then
INSERT INTO table
(
id,
account
)
values
(
tseq_id.nextval,
:p6_account,
);
else
update table set "all columns" where id = :p6_internal_id;
end if ;
This says
ORA-00927: missing equal sign
for the update set "all columns" line.
I don't know how to fix this. How do I set the value of all the columns where id is what I enter?
Based on your comments, you just need to change that line to:
update table set account = :p6_account where id = :p6_internal_id;
You don't need to set the id column to :p6_internal_id as you know it already has that value - since you're using it in the where clause.
There is no magic value of '"all columns"' that would allow every column to be updated at once, not least because you need to supply a value that corresponds to every column anyway, and in the right order.
If you have multiple columns to set then you have to list them all explicitly, with each column/value pair separated by commas; e.g. with a few made-up columns and bind variables:
update table set account = :p6_account,
name = :p6_name,
amount := p6_amount
where id = :p6_internal_id;
You can see the required syntax in the documentation.

PL/SQL Procedure data freezing (reserving random lotto ticket)

I am using a stored procedure to select a "Random" row from Available_Tickets table, after selection if the user like the number, and buy the ticket, the row will be deleted from the table.
my procedure looks like this:
CREATE OR REPLACE GET_RANDOM_TICKET (RESULT OUT INTEGER) IS
co,mn,mx integer;
BEGIN
SELECT COUNT(ID) , MIN(ID) ,MAX(ID) INTO CO,MN,MX FROM TICKETS;
SELECT TICKET_NUMBER INTO RESULT FROM (
SELECT TICKET_NUMBER
FROM TICKETS WHERE ID >= DBMS_RANDOM(MN,MX)
) WHERE ROWNUM = 1;
END GET_RANDOM_TICKET;
if the user agrees on the returned number the selected row is deleted.
can I get in a worst case scenario where the row with max(id) is delete after executing the first select statement ?
edit 1----
Would the two SELECT statements see the same data in-spite off the changes in the table? and why?
i would redesign it as below
1) add a column (ticket status [free,reserved,sold]) to mark the returned ticket as reserved until the user confirmed his selection
2) use a cursor with for update clause to update that ticket status column after returning it to the user - also add where condition for free tickets
3) check ticket status again after user confirmation if it still reserved then update to sold. (in the very slim chance that 2 users ran the program in the same time and got the same number one of them will get the number and the other one should receive error message since the ticket is not reserved anymore.
hope that help

Selecting parameter from values of a SQL Query

I need to produce a report that selects a set of values from a database table based on a company. I would like the user to be able to select the name of the company from a list of available companies. The companies have 2 associated unique database ID code number. Based on what companies the user selects I need the sql query to pass to the parameter both unique codes to the parameter.
So, in short, how do I create a sql query that would show the company names and when selecting the company would then select both unique codes based on the company name I select from a single select drop down. Use the value selected from that drop-down list to run the SQL query in the report itself?
Thanks for any help or advice you can offer!
Pass the company name to to your stored proc instead of the two unique codes, then find the codes for the company inside your procedure.
CREATE someProc (#Company VARCHAR(100))
AS BEGIN
DECLARE #ID1 INT, #ID2 INT
SELECT #ID1 = someID1, #ID2 = someID2
FROM someDatabase
WHERE companyName=#Company

Correct this sql statement for Insert into, select, delete

INSERT INTO Checkout(ProductID, MemberID, Quantity)
SELECT ProductID, MemberID, Quantity
FROM Cart
WHERE (MemberID = MemberID)
DELETE FROM CART WHERE (MemberID = MemberID)
The sql statement is workable until the Select, WHERE part but once I add the delete statement then the error (syntax error missing operator in query expression) comes out. The second MemberID is a value I gave for first MemberID parameter. Please help me to solve this as after I transfer the data from first table to second table then I need to delete the data from first table.
[Edit] Thanks to you all suggestions and now I realized that for WHERE (MemberID = MemberID)
will import entire table to new table and this statement also will delete the entire table contents. What can I do to make sure that the sql statement only delete the particulars members item?
Main Page>Member login page>Buy something>Item stored in shopping cart database (with member id)>display only particular member's bought item in shopping cart> proceed to checkout(only display that member item, delete shopping cart item)
The problem is with the second "MemberID". This needs to be a constant or have a variable name that doesn't conflict with the field name. A number of techniques for disambiguation are shown in a related SO post: How do you avoid column name conflicts?
You didn't mention what version of SQL Server you're using - but you might be able to use the OUTPUT clause for the DELETE statement to achieve what you're looking for. The OUTPUT clause was introduced in SQL Server 2005, so if you're on 2005 or newer, this code snippet should work for you:
Try this:
DELETE FROM dbo.CART
OUTPUT deleted.ProductID, deleted.MemberID, deleted.Quantity
INTO dbo.Checkout(ProductID, MemberID, Quantity)
WHERE MemberID = #MemberID
Basically this runs the DELETE statement against your dbo.Cart table, and it captures what rows have been deleted; those are then in turn inserted into the dbo.Checkout table.
Also - that condition in the WHERE clause seems quite funny - basically, this will select and thus delete all rows from your table......
Update: I'm assuming you somehow store the relevant member's ID in #MemberID and use that to select the rows to delete from the dbo.Cart table..
Store your passing data to a newly declared variable and use that variable to everywhere as below, this will work fine, thanks
DECLARE #PassedMemberID INT
SET #PassedMemberID = MemberID --Store your passing MemberID here for later use
INSERT INTO Checkout(ProductID, MemberID, Quantity)
SELECT ProductID, MemberID, Quantity
FROM Cart
WHERE (MemberID = #PassedMemberID)
DELETE FROM CART WHERE (MemberID = #PassedMemberID)