Unexpected results for DELETE FROM in SQL Server - sql-server

Something rare its happens in my code.
Check this:
if object_id('inscriptos') is not null
drop table inscriptos;
if object_id('socios') is not null
drop table socios;
create table socios
(
numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
create table inscriptos
(
numerosocio int not null,
deporte varchar(20) not null,
matricula char(1),-- 'n' o 's'
primary key(numerosocio, deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio) references socios(numero)
);
GO
insert into socios values('23333333', 'Alberto Paredes', 'Colon 111');
insert into socios values('24444444', 'Carlos Conte', 'Sarmiento 755');
insert into socios values('25555555', 'Fabian Fuentes', 'Caseros 987');
insert into socios values('26666666', 'Hector Lopez', 'Sucre 344');
insert into inscriptos values(1, 'tenis', 's');
insert into inscriptos values(1, 'basquet', 's');
insert into inscriptos values(1, 'natacion', 's');
insert into inscriptos values(2, 'tenis', 's');
insert into inscriptos values(2, 'natacion', 's');
insert into inscriptos values(2, 'basquet', 'n');
insert into inscriptos values(2, 'futbol', 'n');
insert into inscriptos values(3, 'tenis', 's');
insert into inscriptos values(3, 'basquet', 's');
insert into inscriptos values(3, 'natacion', 'n');
insert into inscriptos values(4, 'basquet', 'n');
And here comes the error that I don't understand, I must delete all the rows where in the field "registration" = "n", as you can see there are only 4 records where the value "n" appears in the field registration. But in the following query deletes 8 RECORDS instead of deleting 4 RECORDS.
CODE
DELETE FROM inscriptos
WHERE numerosocio IN (SELECT s.numero
FROM socios AS s
JOIN inscriptos AS i ON (i.numerosocio = s.numero)
WHERE i.matricula = 'n');
Do you know why this happens? I really can't understand it
THANKS!

Your inner SELECT returns this:
numero
------
2
2
3
4
And so your DELETE becomes
DELETE FROM inscriptos
WHERE numerosocio IN (2, 3, 4)
If you check what rows match that condition:
SELECT * FROM inscriptos
WHERE numerosocio IN (2, 3, 4)
you get this result - 8 rows - and those will be deleted:
numerosocio deporte matricula
-----------------------------------
2 basquet n
2 futbol n
2 natacion s
2 tenis s
3 basquet s
3 natacion n
3 tenis s
4 basquet n
So what exactly do you want to delete??
How about this:
DELETE FROM inscriptos
WHERE matricula = 'n'
This would delete those 4 rows with matricula = 'n' - why do you even need that subquery?!?!

Related

Query for relationships between rows

I need to find a relation between multiple person in single table, for example I have the below table:
Guests Table
so I need by sql script to say Guest 123 and 456 they checked in together to the same hotel in the same time 80% and so on...
Kindly support.
It's a little complicated so I've broken it down into multiple subqueries for you using a CTE with a matched key.
This will produce a series of matched pairs - for the primary guest and secondary guest with ratios of how often they stay together rather than just check in.
Setup:
create table temp(
hotelID integer,
checkInDate date,
guestID integer
)
insert into temp values (101, '2020/06/01', 123)
insert into temp values (101, '2020/06/01', 456)
insert into temp values (102, '2020/06/15', 123)
insert into temp values (102, '2020/06/15', 456)
insert into temp values (103, '2020/06/30', 123)
insert into temp values (103, '2020/06/30', 456)
insert into temp values (104, '2020/07/15', 123)
insert into temp values (104, '2020/07/15', 789)
insert into temp values (105, '2020/07/01', 456)
insert into temp values (105, '2020/07/01', 789)
Query:
with keyCte as (
select
distinct cast(hotelID as varchar(3)) + cast(checkInDate as varchar(10)) as myKey,
guestID
from temp
)
select
guestPrime
, guestTwo
, instances as guestPrimeStays
, matches as guestTwoMatches
, cast(matches as float) / cast(instances as float) as hitRate
from (
select
guestID
, count(*) as instances
from keyCte
group by guestID
) sq3
join (
select
guestPrime
, guestTwo
, count(*) as matches
from (
select
keyCte.guestID as guestPrime
, kcte.guestID as guestTwo
from keyCte
join keyCte kcte on kcte.myKey = keyCte.myKey and kcte.guestID != keyCte.guestID
) sq
group by guestPrime, guestTwo
) sq2 on sq2.guestPrime = guestID

How to filter a table against a filtered table

I have a code table containing a list of sports code. And I have another table containing a list of staff that could contain multiple sports code.
I want to return only the staff whose sports code can cover that in the code table.
Like this:
In this case Jason have every code in the code table and Jackson is one code short (codeID 3) So only Jason is return.
Declare #code table
(
codeID varchar(4),
codeDes varchar(72)
Primary Key(codeID, codeDes)
)
Insert into #code
Values ('1', 'apple picking'), ('2', 'pear picking'), ('3', 'farming')
Declare #staff table
(
staffID int,
name varchar(8),
codeID varchar(4)
)
Insert into #staff
Values (1, 'Jason', '1'), (1, 'Jason', '2'),
(1, 'Jason', '3'), (1, 'Jason', '4'),
(2, 'Jackson', '1'), (2, 'Jackson', '2')
You can try below sample assumption staff holds unique code.
SELECT staffId, Name
FROM #staff s
INNER JOIN #code c ON c.codeID = s.codeID
GROUP BY StaffId, Name
HAVING COUNT(DISTINCT s.CodeId) = (SELECT COUNT(1) FROM #code)

Combining results of 2 tables with condition

I have two tables whose results I am trying to combine.
Create table dbo.streetaddr1(HomeID INT,Address varchar(200));
INSERT INTO dbo.streetaddr1 VALUES(1, '656 ave.');
INSERT INTO dbo.streetaddr1 VALUES(2,'B-6 ');
INSERT INTO dbo.streetaddr1 VALUES(3,'13 villa ');
Create table dbo.streetaddr2(HomeID INT,Address varchar(200));
INSERT INTO dbo.streetaddr2 VALUES(1, '656 ave.');
INSERT INTO dbo.streetaddr2 VALUES(2,'B-6 6th avene');
INSERT INTO dbo.streetaddr2 VALUES(4,'25 Main street');
INSERT INTO dbo.streetaddr2 VALUES(5,'135 Elm St ');
If a HomeID exists in dbo.streetaddr1, we pick Address from that even though it also exists in dbo.streetaddr2 we do not
pick it. If a HomeID does not exists in dbo.streetaddr1 then we pick those addresses from dbo.streetaddr2
Expected output table is as below:
Create table dbo.outputtable(HomeID INT,Address varchar(200));
INSERT INTO dbo.outputtable VALUES(1, '656 ave.');
INSERT INTO dbo.outputtable VALUES(2,'B-6 ');
INSERT INTO dbo.outputtable VALUES(3,'13 villa ');
INSERT INTO dbo.outputtable VALUES(4,'25 Main street');
INSERT INTO dbo.outputtable VALUES(5,'135 Elm St ');
How can I do that?
thanks
Rs
Try this
SELECT COALESCE(S1.HOMEID,S2.HOMEID) AS HOMEID,
COALESCE(S1.ADDRESS,S2.ADDRESS) AS ADDRESS
FROM streetaddr1 S1
full join streetaddr2 s2 on s1.HomeId = s2.HomeId

Smart Many to Many Query

I have a list of item descriptions in a c# application. What I want is when I select
1 or 2 or more item descriptions of that list (checkbox list) to predict via an sql query to a many to many table what my item is (minimizing each time the possible predictions);
For example
item 1: white,green,blue
item 2: white,red,cyan
item 3: red,blue,purple
user should select from a check list
white->query will return item 1,2
white&green->query will return only item 1
From your humble description of the problem, I suppose you want something like this:
CREATE TABLE items (
item_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
name VARCHAR(100) NOT NULL
)
CREATE TABLE colors (
color_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
name VARCHAR(100) NOT NULL
)
CREATE TABLE items_colors (
item_id INT NOT NULL FOREIGN KEY REFERENCES items(item_id),
color_id INT NOT NULL FOREIGN KEY REFERENCES colors(color_id),
PRIMARY KEY(item_id, color_id),
)
INSERT INTO items(name) VALUES ('item 1')
INSERT INTO items(name) VALUES ('item 2')
INSERT INTO items(name) VALUES ('item 3')
INSERT INTO colors(name) VALUES ('white')
INSERT INTO colors(name) VALUES ('green')
INSERT INTO colors(name) VALUES ('blue')
INSERT INTO colors(name) VALUES ('red')
INSERT INTO colors(name) VALUES ('cyan')
INSERT INTO colors(name) VALUES ('purple')
INSERT INTO items_colors(item_id, color_id) VALUES (1, 1)
INSERT INTO items_colors(item_id, color_id) VALUES (1, 2)
INSERT INTO items_colors(item_id, color_id) VALUES (1, 3)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 1)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 4)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 5)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 3)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 4)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 6)
SELECT i.*
FROM items i
WHERE 2 = (
SELECT COUNT(*)
FROM items_colors ic
JOIN colors c
ON ic.color_id = c.color_id
WHERE i.item_id = ic.item_id
AND c.name IN ('white', 'green')
)
Within "IN" clause you should provide list of values that user has selected in the UI (you have to build list of parameters dynamically). You also have to provide number of elements that user has selected ("2" in my example solution).
So the query in application will look like this:
SELECT i.*
FROM items i
WHERE #count = (
SELECT COUNT(*)
FROM items_colors ic
JOIN colors c
ON ic.color_id = c.color_id
WHERE i.item_id = ic.item_id
AND c.name IN (#color1, #color2, ..., #colorN)
)
(Where #count is the number of #colorX parameters.)

Recursive Query using CTE in SQL Server 2005

OK, here's what I'm trying to do. I'm using a CTE query in MSSQL2005. The objective of the query is to recurse through Parent child relationships of product categories and return the number of products under each category (this includes any products contained in children categories)
My current version only returns the product count for the category being displayed. It's not accounting for products that may be contained within any of its children.
The database dump to reproduce the problem, along with the query I used and explanation follows below:
CREATE TABLE [Categories] (
[CategoryID] INT,
[Name] NCHAR(150)
)
GO
/* Data for the `Query_Result` table (Records 1 - 5) */
INSERT INTO [Categories] ([CategoryID], [Name])
VALUES (942, N'Diagnostic Equipment')
GO
INSERT INTO [Categories] ([CategoryID], [Name])
VALUES (943, N'Cardiology')
GO
INSERT INTO [Categories] ([CategoryID], [Name])
VALUES (959, N'Electrodes')
GO
INSERT INTO [Categories] ([CategoryID], [Name])
VALUES (960, N'Stress Systems')
GO
INSERT INTO [Categories] ([CategoryID], [Name])
VALUES (961, N'EKG Machines')
GO
CREATE TABLE [Categories_XREF] (
[CatXRefID] INT,
[CategoryID] INT,
[ParentID] INT
)
GO
/* Data for the `Query_Result` table (Records 1 - 5) */
INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID])
VALUES (827, 942, 0)
GO
INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID])
VALUES (828, 943, 942)
GO
INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID])
VALUES (928, 959, 943)
GO
INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID])
VALUES (929, 960, 943)
GO
INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID])
VALUES (930, 961, 943)
GO
CREATE TABLE [Products_Categories_XREF] (
[ID] INT,
[ProductID] INT,
[CategoryID] INT
)
GO
/* Data for the `Query_Result` table (Records 1 - 13) */
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252065, 12684, 961)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252066, 12685, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252067, 12686, 960)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252068, 12687, 961)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252128, 12738, 961)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252129, 12739, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252130, 12740, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252131, 12741, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252132, 12742, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252133, 12743, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252134, 12744, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252135, 12745, 959)
GO
INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID])
VALUES (252136, 12746, 959)
GO
CREATE TABLE [Products] (
[ProductID] INT
)
GO
/* Data for the `Query_Result` table (Records 1 - 13) */
INSERT INTO [Products] ([ProductID])
VALUES (12684)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12685)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12686)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12687)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12738)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12739)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12740)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12741)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12742)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12743)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12744)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12745)
GO
INSERT INTO [Products] ([ProductID])
VALUES (12746)
GO
Here's the CTE query I was using:
WITH ProductCategories (CategoryID, ParentID, [Name], Level)
AS
(
-- Anchor member definition
SELECT
C.CategoryID,
CXR.ParentID,
C.Name,
0 AS Level
FROM
Categories C,
Categories_XRef CXR
WHERE
C.CategoryID = CXR.CategoryID
AND CXR.ParentID = 0
UNION ALL
-- Recursive member definition
SELECT
C.CategoryID,
CXR.ParentID,
C.Name,
Level + 1
FROM
Categories C,
Categories_XRef CXR,
ProductCategories AS PC
WHERE
C.CategoryID = CXR.CategoryID
AND CXR.ParentID = PC.CategoryID
)
SELECT
PC.ParentID,
PC.CategoryID,
PC.Name,
PC.Level,
(SELECT
Count(P.ProductID)
FROM
Products P,
Products_Categories_XREF PCXR
WHERE
P.ProductID = PCXR.ProductID
AND PCXR.CategoryID = PC.CategoryID
) as ProductCount
FROM
Categories C,
ProductCategories PC
WHERE
PC.CategoryID = C.CategoryID
AND PC.ParentID = 943
ORDER BY
Level, PC.Name
First, change the "PC.ParentID" to 943. You'll see three records returned showing the product Count for each category being displayed.
Now, change the ParentID from 943 to 942 and re-run it. You'll now see 1 result returned called "Cardiology", but it shows 0 products
Under this category, there are children (who you previously saw) who contain products. My big question is, at this level (Parent 942) how can I make it count the products contained in the children below to show 13 as the "ProductCount" I'm kinda thinking I may need one more recursion method. I tried that, but had no success.
I'm open to a stored procedure that would do what I'm looking for. I'm not set on one particular way. So any other suggestions would be appreciated.
edit OK having actually read the requirements and thought a bit this is actually quite easy (I think!)
The point is that we want two things: the category hierarchy, and a count of products. The hierarchy is done by a recursive CTE, and counting is done outside that:
-- The CTE returns the cat hierarchy:
-- one row for each ancestor-descendant relationship
-- (including the self-relationship for each category)
WITH CategoryHierarchy AS (
-- Anchor member: self relationship for each category
SELECT CategoryID AS Ancestor, CategoryID AS Descendant
FROM Categories
UNION ALL
-- Recursive member: for each row, select the children
SELECT ParentCategory.Ancestor, Children.CategoryID
FROM
CategoryHierarchy AS ParentCategory
INNER JOIN Categories_XREF AS Children
ON ParentCategory.Descendant = Children.ParentID
)
SELECT CH.Ancestor, COUNT(ProductID) AS ProductsInTree
-- outer join to product-categories to include
-- all categories, even those with no products directly associated
FROM CategoryHierarchy CH
LEFT JOIN Products_Categories_XREF PC
ON CH.Descendant = PC.CategoryID
GROUP BY CH.Ancestor
The results are:
Ancestor ProductsInTree
----------- --------------
942 13
943 13
959 9
960 1
961 3
I am indebted to this article by the inestimable Itzik Ben-Gan for getting my thinking kick-started. His book 'Inside MS SQL Server 2005: T-SQL Querying' is highly recommended.
Your WHERE statement limits the result to one parent. If you'd like to see all children below 942, specify 942 as the root in the CTE. For example:
WITH CTE (CategoryID, ParentID, [Name], [Level])
AS
(
SELECT C.CategoryID, CXR.ParentID, C.Name, 0 AS Level
FROM Categories C
INNER JOIN Categories_XRef CXR ON C.CategoryID = CXR.CategoryID
WHERE CXR.CategoryID = 943
UNION ALL
SELECT C.CategoryID, CXR.ParentID, C.Name, Level + 1
FROM Categories C
INNER JOIN Categories_XRef CXR ON C.CategoryID = CXR.CategoryID
INNER JOIN CTE PC ON PC.CategoryID = CXR.ParentID
)
SELECT * FROM CTE
By the way, can categories can have multiple parents? If not, consider eliminating the Categories_XREF table and storing ParentID in the Categories table.

Resources