由于我无法建立联接以获得预期结果,因此我开始认为整个架构可能是错误的。
模型(仅限相关领域):
public class AspNetUsers // this is ASPNET default identity table modified
{
public string Id { get; set; }
public int GeoID { get; set; } // FK to GeoData PK
public string Email { get; set; }
public partial class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CategoryID { get; set; } // FK to Category PK
public string UserID { get; set; } // FK to AspNetUsers PK
public partial class Category
{
public int ID { get; set; }
public string Name { get; set; }
public class GeoData
{
public int ID { get; set; }
public DbGeography GeoLocation { get; set; }
public class WishList
{
public int ID { get; set; }
public string userEmail { get; set; } // FK to AspnetUsers 'Email'
public int frequency { get; set; }
public int category { get; set; } // FK to Category PK
public int range { get; set; }
public int geoid { get; set; } // FK to Geodata PK
我们的想法是:我们有产品和类别。产品与用户有关。产品模型中的userID FK说明了这一点,在每个用户注册时,将每个产品链接到AspNetUsers表中的所有者,通过aspnet身份登录ecc ... 在设置产品之前,用户必须自己进行地理定位,以便其他用户可以方便地对其产品进行地理定位(搜索)。 Geodata表占全球坐标,邮政编码,地名ecc .. 现在到愿望清单。每个用户可以设置'n'愿望列表,设置他们感兴趣的类别,以及该位置的位置和范围。 Whislists的结果由sql server通过电子邮件发送给用户,计划在“频率”字段。
我不确定这是最好的数据库架构。有时您只是从一些构建块(AspNetUsers,Products,Categories)开始,逐步添加其他功能。 无论如何..这是一个基本的SELECT,用于根据用户的不同愿望清单构建要发送的电子邮件:
DECLARE C1 CURSOR READ_ONLY
FOR
SELECT [userEmail], [frequency], [category],[range], w.[geoid], [searchCity], u.UserName, g.[GeoLocation]
FROM WishLists as w
JOIN AspNetUsers as u ON w.userEmail = u.Email
JOIN GeoData_IT as g ON g.ID = w.geoid
OPEN C1;
FETCH NEXT FROM C1 INTO
@userEmail, @frequency, @category, @range, @geoid, @searchCity, @userName, @GeoLocation
WHILE @@FETCH_STATUS = 0
BEGIN
IF @geoid > 0
BEGIN
SELECT p.ID, c.Name, p.Name, g.PlaceName
FROM WishLists as w
RIGHT OUTER JOIN GeoData_IT AS g ON w.geoid = g.ID
JOIN AspNetUsers AS u ON g.ID = u.GeoID
JOIN Products as p on u.Id = p.UserID
JOIN Categories AS c ON p.CategoryID = c.ID
WHERE g.GeoLocation.STDistance(@GeoLocation) <= (@range*5000)
END
FETCH NEXT FROM C1 INTO
@userEmail, @frequency, @category, @range, @geoid, @searchCity, @userName, @GeoLocation
END
CLOSE C1;
DEALLOCATE C1;
GO
此时我甚至没有介绍'类别'复杂功能,只是检查wishlist是否包含一个相关的大地水准面(如果大地水准面> 0)试图为每个愿望清单提取属于其地理位置所在的用户的任何产品。从给定的大地水准面给出范围。 然而,我只是在某些愿望清单上随机获得了一些重复的结果,我无法弄清楚原因。
看起来很好:
1 Nursery Loved Crib Bale Genoa
2 Baby products Crib Genoa
3 Baby products Cot Bed Genoa
4 Feeding Circus Crib Bale Genoa
虽然这显示重复:
1555 Baby products this uaga product Recco
1555 Baby products this uaga product Recco
1556 Automotive uaga product Recco
1556 Automotive uaga product Recco
整个架构是否失败或只是SELECT?
答案 0 :(得分:0)
如果您打算使用存储过程或游标(尽可能避免游标,尝试使用不同的技术,如CTE),那么您一定要先使用数据库。使用代码优先方法没有任何好处。
那就是说,你显然没有使用ICollection声明表之间的关系。
此外,您没有使用数据注释来使用[KEY]确定主键或使用[MAXLENGTH(n)]限制字符串列的大小。您的表没有主键和外键,因此所有字符串列都是NVARCHAR(MAX)。结果你的桌子会占用很多空间。
你得到的是笛卡尔积,它是预期的。如果您想在不深入了解查询逻辑的情况下避免使用它,请使用DISTINCT或GROUP BY。
答案 1 :(得分:-1)
架构没有任何问题,问题是SELECT在提取时没有引用WishLists ID。这是更正后的代码:
DECLARE C1 CURSOR READ_ONLY
FOR
SELECT w.ID, w.userEmail, w.category, w.range, w.geoid, w.searchCity, u.UserName, g.GeoLocation
FROM WishLists as w JOIN AspNetUsers as u ON w.userEmail = u.Email JOIN GeoData_IT as g ON g.ID = w.geoid
WHERE w.frequency = 1 order by w.ID
OPEN C1;
FETCH NEXT FROM C1 INTO
@WishListID, @userEmail, @category, @range, @geoid, @searchCity, @userName, @GeoLocation
WHILE @@FETCH_STATUS = 0
BEGIN
if @geoid > 0
begin
if @category > 0
begin
SELECT p.ID, c.Name, p.Name, g.PlaceName
FROM Products as p
JOIN Categories AS c ON p.CategoryID = c.ID
JOIN AspNetUsers AS u ON p.UserID = u.Id
JOIN WishLists AS w ON @WishListID = w.ID
JOIN GeoData_IT AS g ON u.GeoID = g.ID
WHERE p.IsApproved = 1 AND p.IsDeleted = 0 AND p.DateExpire > convert(date, getdate())
AND w.IsDeleted = 0 AND g.GeoLocation.STDistance(@GeoLocation) <= (@range*5000)
AND p.CategoryID = @category
order by p.ID
end -- category != 0
end -- @geoid > 0
FETCH NEXT FROM C1 INTO
@WishListID, @userEmail, @category, @range, @geoid, @searchCity, @userName, @GeoLocation
END
CLOSE C1;
DEALLOCATE C1;
关键线是
JOIN WishLists AS w ON @WishListID = w.ID