SQL SELECT JOIN和数据库架构

时间:2017-03-27 17:32:52

标签: sql-server database tsql

由于我无法建立联接以获得预期结果,因此我开始认为整个架构可能是错误的。

模型(仅限相关领域):

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?

2 个答案:

答案 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