SQL script to not allow insert - sql

I have a query that maps all products to some customer levels. In this case levels 0,5,7 and 8
DELETE FROM ProductCustomerLevel
WHERE CustomerLevelID IN (0, 5, 7, 8)
INSERT ProductCustomerLevel
(
ProductID,
CustomerLevelID
)
SELECT ProductID,
CustomerLevel
FROM dbo.Product p
CROSS JOIN (
SELECT 0 AS CustomerLevel UNION ALL
SELECT 5 UNION ALL
SELECT 7 UNION ALL
SELECT 8
)c
The reason that the Delete begins the SQL script is so that any product that may have been deleted or unmapped from the sites is counted for
Basically this maps all products in a database to these customer levels so that they get a discount.
I now need to create a new customer level, example number 9. These will only have 1 or 2 products applied to it.
How can I change the SQL above so that it does not map those products already in Customer Level 9 to levels 0,5,7 and 8

You can just append a WHERE clause to the end that excludes all products that have an existing connection with level 9;
WHERE ProductID NOT IN (
SELECT ProductID FROM ProductCustomerLevel
WHERE CustomerLevelID=9
)
An SQLfiddle to test with.

Related

Search data in sql on behalf of list of parameters ,

Hi All i am unable to create a query in sql i want to get all employee who's contain the product which i passed in parameter
Ex, i if passed product id 11,12 then its should be return only DeliveryBoyId1 and 2 and if passed the product id 11 then its should be return only DeliveryBoyId 1,2,3 and if i passed productid 11,12,16 then its should return 0 record because there is no delivery boy assigned the product id 11,12,16
I don't know what your table is called so I'm calling it dbo.Delivery. Try this out:
;with CTE as (
select distinct DeliveryBoyId --get all the boys who delivered product 11
from dbo.Delivery
where ProductId = 11
union all --combine the above results with the below
select distinct DeliveryBoyId --get all the boys who delivered product 12
from dbo.Delivery
where ProductId = 12
)
select DeliveryBoyId
from CTE
group by DeliveryBoyId
having count(1) = 2 --get all the boys who appear twice in the above table, once for each product
If you want to match additional products, you can add to the CTE section for other product IDs.
If you want a single solution for any number of products, you can use this instead (which may be a little less readable but more concise and easier to maintain):
select DeliveryBoyId
from (
select distinct DeliveryBoyId, ProductId
from dbo.Delivery
where ProductId in (11, 12)
) s
group by DeliveryBoyId
having count(1) = 2 --number matches number of products you need to match

Split a row into multiple rows based on a column value SQL

I have the following "Order Table" :
Item Quantity
pencil 2
pen 1
Notebook 4
I need the result like :
Item Quantity
pencil 1
pencil 1
pen 1
Notebook 1
Notebook 1
Notebook 1
Notebook 1
You didn't specify which RDBMS you are using, so how you generate the numbers will depend on that (maybe a recursive CTE for SQL Server, using DUAL for Oracle, etc.). I've only written code to handle the data that you've shown, but you'll obviously need to account for numbers larger than four in the final solution.
SELECT
MT.sr_no,
MT.item_name,
1 AS quantity
FROM
My_Table MT
INNER JOIN
(
SELECT 1 AS nbr UNION ALL SELECT 2 AS nbr UNION ALL
SELECT 3 AS nbr UNION ALL SELECT 4 AS nbr
) N ON N.nbr <= MT.quantity
You can use the recursive query using common table expression to generate number duplicate rows according to the quantity field as below
WITH cte (sno,item,quantity,rnum)
AS
(
SELECT sno,item,quantity, 1 as rnum
FROM [Order]
UNION ALL
SELECT cte.sno,cte.item,cte.quantity, rnum+1
FROM [Order] JOIN cte ON [Order].sno = cte.sno
AND cte.rnum < [Order].quantity
)
SELECT item,1 AS Quantity
FROM cte
ORDER BY sno

SQL Server - tsql join/filtering issue

Probably the wrong title, but I can't summarise what I'm trying to do nicely. Which is probably why my googling hasn't helped.
I have a list of Discounts, and a list of TeamExclusiveDiscounts (DiscountId, TeamId)
I call a stored procedure passing in #TeamID (int).
What I want is all Discounts except if they're in TeamExclusiveDiscounts and don't have TeamID matching #TeamId.
So the data is something like
Table Discount:
DiscountID Name
-----------------------
1 Test 1
2 Test 2
3 Test 3
4 Test 4
5 Test 5
Table TeamExclusiveDiscount:
DiscountID TeamID
-----------------------
1 10
2 10
2 4
3 8
Expected results:
searching for TeamID = 10 I should get discounts 1,2,4,5
searching for TeamID = 5 I should get discounts 4, 5
searching for TeamID = 8 I should get discounts 3, 4, 5
I've tried a variety of joins, or trying to update a temp table to set whether the discount is allowed or not, but I just can't seem to get my head around this issue.
So I'm after the T-SQL for my stored procedure that will select the correct discounts (SQL Server). Thanks!
SELECT D.DiscountID FROM Discounts D
LEFT JOIN TeamExclusiveDiscount T
ON D.DiscountID=T.DiscountID
WHERE T.TeamID=#TeamID OR T.TeamID IS NULL
SQLFIDDLE for TEST
Can you try this - it only selects records where there is a teamdiscount record with the team or no teamdiscount record at all.
SELECT * FROM Discounts D
WHERE
EXISTS (
SELECT 1
FROM TeamExclusiveDiscount T
WHERE T.DiscountID = D.DiscountID
AND TeamID = #TeamID
)
OR
NOT EXISTS (
SELECT 1
FROM TeamExclusiveDiscount T
WHERE T.DiscountID = D.DiscountID
)
I like to translate the English description directly into SQL (atleast as a first pass):
"All Discounts except if they're in TeamExclusiveDiscounts and don't have TeamID matching #TeamId."
SELECT *
FROM Discounts D -- All Discounts
WHERE D.DiscountID NOT IN -- except if they're in TeamExclusiveDiscounts
(SELECT T.DiscountID
FROM TeamExclusiveDiscount T
WHERE T.DiscountID NOT IN -- and don't have TeamID matching #TeamId.
(SELECT Match.DiscountID
FROM TeamExclusiveDiscount Match
WHERE Match.TeamID = #TeamID)
)

Using SQL to find the total number of customers with over X orders

I've been roasting my brain with my limited SQL knowledge while attempting to come up with a query to run a statistic on my orders database.
Table ORDERS is laid out like this:
CustomerID ProductID (etc)
1 10
1 10
1 11
2 10
4 9
Each purchase is recorded with the customer id and the product ID - there CAN be multiple records for the same customer, and even multiple records with the same customer and product.
I need to come up with a query that can return the amount of customers who bought between X and X distinct products - for example, 3 customers bought less then 5 different products, 10 bought from 5-10 different products, 1 bought over 10 different products.
I'm pretty sure this has something to do with derived tables, but advanced SQL is a new fairly craft to me. Any help would be appreciated!
Try this:
SELECT T1.products_bought, COUNT(T2.cnt) AS total
FROM (
SELECT '<5' AS products_bought, 0 AS a, 4 AS b
UNION ALL
SELECT '5-10', 5, 10
UNION ALL
SELECT '>10', 11, 999999
) T1
LEFT JOIN
(
SELECT COUNT(DISTINCT ProductID) AS cnt
FROM ORDERS
GROUP BY CustomerID
) T2
ON T2.cnt BETWEEN T1.a AND T1.b
GROUP BY a, b
Result:
products_bought total
<5 3
5-10 0
>10 0

SQL return multiple rows from one record

This is the opposite of reducing repeating records.
SQL query to create physical inventory checklists
If widget-xyz has a qty of 1 item return 1 row, but if it has 5, return 5 rows etc.
For all widgets in a particular warehouse.
Previously this was handled with a macro working through a range in excel, checking the qty column. Is there a way to make a single query instead?
The tables are FoxPro dbf files generated by an application and I am outputting this into html
Instead of generating an xml string and using xml parsing functions to generate a counter as Nestor has suggested, you might consider joining on a recursive CTE as a counter, as LukLed has hinted to:
WITH Counter AS
(
SELECT 0 i
UNION ALL
SELECT i + 1
FROM Counter
WHERE i < 100
),
Data AS
(
SELECT 'A' sku, 1 qty
UNION
SELECT 'B', 2
UNION
SELECT 'C', 3
)
SELECT *
FROM Data
INNER JOIN Counter ON i < qty
According to query analyzer, this query is much faster than the xml pseudo-table. This approach also gives you a recordset with a natural key (sku, i).
There is a default recursion limit of 100 in MSSQL that will restrict your counter. If you have quantities > 100, you can either increase this limit, use nested counters, or create a physical table for counting.
For SQL 2005/2008, take a look at
CROSS APPLY
What I would do is CROSS APPLY each row with a sub table with as many rows as qty has. A secondary question is how to create that sub table (I'd suggest to create an xml string and then parse it with the xml operators)
I hope this gives you a starting pointer....
Starting with
declare #table table (sku int, qty int);
insert into #table values (1, 5), (2,4), (3,2);
select * from #table;
sku qty
----------- -----------
1 5
2 4
3 2
You can generate:
with MainT as (
select *, convert(xml,'<table>'+REPLICATE('<r></r>',qty)+'</table>') as pseudo_table
from #table
)
select p.sku, p.qty
from MainT p
CROSS APPLY
(
select p.sku from p.pseudo_table.nodes('/table/r') T(row)
) crossT
sku qty
----------- -----------
1 5
1 5
1 5
1 5
1 5
2 4
2 4
2 4
2 4
3 2
3 2
Is that what you want?
Seriously dude... next time put more effort writing your question. It's impossible to know exactly what you are looking for.
You can use table with number from 1 to max(quantity) and join your table by quantity <= number. You can do it in many ways, but it depends on sql engine.
You can do this using dynamic sql.