sql selecting from different tables based on boolean - sql

I have a simple stored procedure like so:
ALTER PROCEDURE [dbo].[spList_Report]
#id INT
AS
SET NOCOUNT ON
SELECT *
FROM
tblProducts as products
WHERE
product.intID = #id
I have 2 user tables: MainUser and SubUser
Both tables have a foreign key column productID which is related to the primary key intID of the product table intID. They both also have a column emailAddress. The product table also has a bit column isMainUser.
How can I update my stored procedure to return the column emailAddress based on the isMainUser value? So if the value is true it selects the email address from the MainUser table and if its false then it selects the emailAddress from the SubUser table.
E.g what I want is only one emailAddress column:
ALTER PROCEDURE [dbo].[spList_Report]
#id INT
AS
SET NOCOUNT ON
SELECT
products.*
, myUser.emailAddress
FROM
tblProducts as products
WHERE
product.intID = #id

You have left out some important information. I am assuming that
Products can be joined with MainUser on a UserProductID
Products can be joined with SubUser on a UserProductID
There is 1 Main user for each product. (most likely not but that will need to be adressed when you have given us more information)
There is 1 Sub user for each product.
SQL Statement
SELECT products.*
, CASE WHEN isMainUser=1
THEN MainUser.emailAddress
ELSE SubUser.emailAddress
END
FROM tblProducts as products
LEFT OUTER JOIN MainUser mu ON mu.UserProductID = products.UserProductID
LEFT OUTER JOIN SubUser su ON su.UserProductID = products.UserProductID
WHERE product.intID = #id
Note that it is considered bad practice to use a SELECT *. SELECT * should never be present in production code.

Create a view on the two tables and join to that in your proc

Related

How to get a selection from tables related using a many-to-many relationship

I'm new to sql, I've looked at similar questions and answers on the platform, but still couldn't solve my problem.
I have three tables:
CREATE TABLE CartProducts (
Id PRIMARY KEY
ProductId int
Quanity int
)
CREATE TABLE CartCartProducts ( /* <-- many to many table */
CartProductsId PrimaryKey
CartId PrimaryKey
)
CREATE TABLE Cart (
Id PrimaryKey
UserId int
)
Before the query I have the following data:
I know the UserId
I know the ProductId
I know the CartId
I need to get the user's product with the passed product's id and user's id
I tried this:
SELECT
*
FROM
cart_products cp
JOIN cart_cart_products cm2m1 ON cm2m1.cart_id = %d
INNER JOIN cart_cart_products cm2m2 ON cm2m2.cart_products_id = cp.id
I know that using * is not recommended, I will remake it in the future
you always have to join all tables. with their columns, after that you have access to all columns and can extract all information needed.
the use of placehoder and parpameters, i omitted, as i don't know which langua you are using, but a quick search should find you a lot of answers
Following query fund you the quantity of a cart with number 1 of userid 1 and of the product 1
Fromhere you have all possibility, to search for all cart of a user, or all products he purchased
SELECT
cp.Quanity
FROM
cart_products cp
JOIN cart_cart_products cm2m1 ON cm2m1.cart_id = cp.iId
INNER JOIN cart c = c.Id = cm2m1.CartId
WHERE c.UserId = 1 AND c.id = 1 AND cp.ProductId = 1

update email selected from another table using the foreign key relation

I have 3 tables called Contact, APP_User, Customer Table. here I want to select email from my Contact table based on Contact_ID as Foreign key in App_User table and I want to Update the selected email into my Customer table based on App_User_Id as Foreign key in Customer table and primary key in APP_User Table.
Clearly:- I want to fetch email where Contact.contact_ID = APP_User.Contact_ID and Update the fetched email to Customer.emial where APP_User.App_User_Id = Customer.App_User_Id
UPDATE CRM.CRM_CUSTOMER_USER
SET EMAIL = (SELECT EMAIL
FROM QA29.ST_CONTACT
INNER JOIN QA29.ST_APP_USER ON QA29.ST_CONTACT.CONTACT_ID = 129)
WHERE APP_USER_ID = 120;
But it results in:
ORA-01427: single-row subquery returns more than one row
Join condition is missing in the inner query.
There must be multiple rows returned by the following query which is the cause of the issue:
SELECT
EMAIL
FROM
QA29.ST_CONTACT
INNER JOIN QA29.ST_APP_USER ON QA29.ST_CONTACT.CONTACT_ID = 129;
You must restrict this to single record using valid join condition, something like the following:
UPDATE CRM.CRM_CUSTOMER_USER
SET
EMAIL = (
SELECT
EMAIL
FROM
QA29.ST_CONTACT
INNER JOIN QA29.ST_APP_USER
ON QA29.ST_CONTACT.APP_USER_ID = QA29.ST_APP_USER.APP_USER_ID -- OR SOMETHING LIKE THIS
AND QA29.ST_CONTACT.CONTACT_ID = 129
)
WHERE
APP_USER_ID = 120;
Cheers!!

Delete rows from multiple tables with foreign keys

I have three tables
userTable with following rows Id, FirstName, LastName, Email
Product A with following rows Id, UserId(FK), startDate
Product D with following rows Id, UserId(FK), startDate
I want to delete rows from three tables with particular UserId.
What I want to achieve -
Find the id given email (select id from userTable where Email = 'abc.com') - got back id - 3
Delete from Product A where id = 3
Delete from Product D where id = 3
Delete from userTable where id = 3
I want to create a script.
Any help is appreciated or learning reference would be great.
Declare a variable and save the id to that variable. Use that Id for the delete query.
DECLARE #Id INT;
SELECT #Id=id
FROM userTable
WHERE Email = 'abc.com'
DELETE FROM Product A WHERE id = #Id
DELETE FROM Product D WHERE id = #Id
DELETE FROM userTable WHERE id = #Id
But I guess in your case you have UserId as the FK so you should be trying this:
DELETE FROM Product A WHERE UserId= #Id
DELETE FROM Product D WHERE UserId= #Id
DELETE FROM userTable WHERE id = #Id
Note: If you want to do the same thing what's there in question, go for 1st one. If you want to delete the relevant user records from A and D table then go for the 2nd method where you are deleting the records using the FK.
From what I can gather from your question you want something like this:
DELETE FROM
userTable,
ProductA,
ProductB
WHERE
userTable.Id = (select Id from userTable where Email like 'abc.com') AND
userTable.Id = ProductA.Id AND
userTable.Id = ProductB.Id;
And the Email in the subquery in the WHERE clause would be your input parameter
DISCLAIMER: From a Sybase/SQL Anywhere background, this would be possible, I'm not sure if it could be done in SQL-server.

Microsoft SQL query multiple condition

I have an Attributes table which has a set of attributes identified by a unique number and then followed by their description - An example schema is
ID - AttributeName
with some sample data below
1 = FirstName
2 = LastName
3 = Phone
I then have an employees table which for the sake of simplicity has the following schema
ID - PersonID
AttribueID - INT Foreign key to the above attributes table
I need to create a stored proc that given a condition will return records based on one of the following conditions
If I pass in a 1 to the stored procedure the proc should return all records from the Person table who match the attribute ID 1 (First name)
If I pass in a 2 to the stored procedure the proc should return all records from the Person table who * DO NOT * match the attribute ID 1 (First name)
If I pass in a 3 to the stored procedure the proc should return all records from the Person table
I could do the following but feel it is not the best way this could be performed
DECLARE #IntID INT = 1 -- Set as 1 just for exmple
IF #IntID =1
BEGIN
SELECT * FROM Person where AttributeID IN (SELECT ID from Attributes Where ID =1) -- match on attribute 1
END
ELSE IF #IntID = 2
BEGIN
SELECT * FROM Person where AttributeID NOT IN (SELECT ID from Attributes Where ID =1) -- do not match on attribute 1
END
ELSE
BEGIN
SELECT * FROM Person where AttributeID IN (SELECT ID from Attributes) -- return match on all attributes
END
The above example has an extremely simple SELECT statement - in the real SQL there is a much larger set
Thanks in advance
If you don't wanna use dynamic sql then you may try this. And your query is too simple that for performance optimization, you may look to the table indexes for that.
DECLARE #IntID INT = 1 -- Set as 1 just for exmple
IF #IntID = 1 OR #IntID = 2
BEGIN
SELECT A.*
FROM Person A
LEFT JOIN Attributes B ON A.AttributeID = B.ID AND B.ID = 1
WHERE
A.AttributeID IS CASE #IntID WHEN 1 THEN NOT NULL WHEN 2 THEN NULL END
END
ELSE
BEGIN
SELECT A.*
FROM Person A
INNER JOIN Attributes B ON A.AttributeID = B.ID
END

SQL Query to find ALL products by user and division?

I am struggling to come up with the SQL query to find the all the products accessible to user under a particular division.
A division can have many products.
Division table has division_id and division_name.
Product table has product_id, product_name and division_id.
I have another table called UserProducts where I have columns like
user_id, division_id and product_id.
In the UI part while assigning products to user, division is selected first and then based on selected division products are populated.
In addition to the products from products table, the product drop down has one more option called as ALL.
When ALL option from product is selected all products under the division are assigned to the user.
But in the User products I do not enter entry for all the products. It has only one entry like
user_id = 1, division_id = 1 and product_id = -1
where -1 says its ALL products under division_id = 1
Also user can have access to many divisions. So User can have access to all products under division A but only two products under divison B.
Now, with this schema how do I get all the products accessible to user under division?
EDIT 1
I will have user id and product id as inputs and i would want to get all the products accessible to given user under given division.
Input : user_id, division_id
output : List of all products by user_id and division_id
Please help.
SELECT product_id, product_name and division_id
FROM Products AS P
WHERE EXISTS (
SELECT *
FROM UserProducts AS U
WHERE U.division_id = P.division_id
AND U.product_id = -1
)
UNION
SELECT product_id, product_name and division_id
FROM Products AS P
WHERE EXISTS (
SELECT *
FROM UserProducts AS U
WHERE U.division_id = P.division_id
AND U.product_id = P.product_id
);
This should do it:
SELECT *
FROM user_products up
JOIN products p ON up.division_id = p.division_id AND (up.product_id = p.product_id OR up.product_id = -1)
WHERE up.user_id = ?????
AND up.division_id = ????
We join from the user_products table onto the products table where either both the division_id and product_id matches, or the division_id matches and the product_id is -1 (thus returning all corresponding products for that division). And finally at the end we restrict to a particular user_id and division id. Simply change the last two lines to change your inputs for example if you wanted to restrict by product instead of division swap:
up.division_id = ????
for
up.product_id = ????
This schema is not recommended as it would propose complexities later. For example if a user has all the products in 1 division but then one of the products is revoked, you will have to remove -1 entry and replace with the remaining assigned products.
However staying with this schema you will need to fetch the products via a Stored Procedure which checks if the value is -1 then pass all the products otherwise just the products that are assigned.
Create PROCEDURE [dbo].[sp_UserProductsbyDivision]
#Division as nvarchar(50),
#User as int output
AS
BEGIN
SET #AllProductsFlag=(select min(product_id) from UserProducts where user_id=#user and division_ID=#Division)
if #AllProductsFlag=-1
Begin
--Select ALL products in that divsion
Select #User, Products.Product_ID from Products where division_id=#division
End
Else
Begin
Select UserProducts.User_ID, Product_ID from UserProducts where User_ID=#User and Division_ID = #Division
End
END
Sorry I haven't been able to create the actual schema and test this but I think this should give you an idea. Debug as necessary!
SELECT DISTINCT
p.product_id,
p.whatever
FROM UserProducts up
INNER JOIN Product p ON up.product_id IN (-1, p.product_id)
WHERE up.user_id = #user_id
AND up.division_id = #division_id