2010-07-25 4 views
0
 int id = 1; 
     string chain = "("; 
     SqlDataReader dr = SqlHelper.ExecuteReader(string.Format("SELECT a.Id as x, c.Id as y From Friends b INNER JOIN Users a ON b.SenderId = a.Id INNER JOIN Users c ON b.ReceiverId = c.Id WHERE (c.Id = {0} OR a.Id = {0}) AND State = '{1}'", id, "ok")); 
     if (dr.HasRows) 
      while (dr.Read()) 
       if (id == int.Parse(dr["y"].ToString())) 
        chain += dr["x"].ToString() + ", "; 
       else 
        chain += dr["y"].ToString() + ", "; 
     if (chain.Length > 1) 
      chain = chain.Substring(0, chain.Length - 2) + ")"; 
     else 
      chain = "(0)"; 
     // Chain has for example => (2, 3, 4, 5) => which are the Ids for Users's Friends 
     string str = "SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic"; 
     str += " FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id "; 
     str += "WHERE SenderId IN "; 
     str += chain; 
     str += " OR ReceiverId IN"; 
     str += chain; 
     str += " Order BY Id desc"; 
     dr = SqlHelper.ExecuteReader(str); 

chain считается пользователем этого пользователя. Кто-нибудь знает, как выполнить этот запрос с помощью JOINS!? Большое спасибо.Помогите с вложенным запросом!

+1

Я думаю, вы должны удалить код C# и перефразировать вопрос, касающийся задействованного SQL. Включите дополнительную информацию о схеме. Вероятно, это даст вам больше ответов. – driis

+0

Очень сложно понять, что вас действительно интересует. Проведенный образец кода очень грязный и трудно понятный. Если вы хотите узнать, как превратить SQL-запрос с WHERE SenderId IN (....) 'в запрос с JOINs, то, пожалуйста, дайте нам только тот SQL-запрос, на который вы смотрите, а не код C#, создающий его ... .... вы делаете это излишне трудным и трудным для людей, чтобы ответить вам ..... –

+0

Предполагается, что «ReceiverId», согласованный в первом запросе, должен иметь право на совпадение «SenderId» во втором? –

ответ

1
SELECT distinct TOP(20) e.*, u1.UserName As Sender, 
u2.UserName As Receiver, u1.Avatar AS SenderPic 
FROM Friends f INNER JOIN Users u 
ON(u.Id = f.SenderId OR u.Id = f.ReceiverId) AND State = 'ok' 
INNER JOIN Events e 
ON(f.SenderId = e.SenderId OR f.SenderId = e.ReceiverId 
OR f.ReceiverId = e.SenderId OR f.ReceiverId = e.ReceiverId) 
INNER JOIN Users u1 
ON (e.SenderId = u1.Id) 
INNER JOIN Users u2 
ON (e.ReceiverId = u2.Id) 
WHERE u.Id = @id; 
2

Сначала попробуйте избавиться от нажатия значений параметров с помощью string.Format в SQL-запросы. Это огромная проблема безопасности.

На ваш запрос. Должен признаться, я немного потерял в вашей конкатенации строк: -P, но если я прав, вы хотите получить информацию о событиях и некоторых пользовательских данных. Насколько я вижу, SenderId и ReciverId уже являются вашими идентификаторами. Если да, то вы можете полностью удалить первый SELECT, и обеспечить идентификатор (в качестве параметра) непосредственно в второе заявление SQL, как это (только SQL):

Edit: Том показал мне недостающую часть (Status = Ok)

ВЫБРАТЬ TOP (20) а. * , b.UserName в качестве отправителя , c.UserName в качестве приемника , b.Avatar в SenderPic ОТ События INNER JOIN пользователи в ON a.SenderId = b.Id INNER JOIN Пользователи c ON a.Receive rId = c.Id ГДЕ a.SenderId = @id ИЛИ a.ReceiverId = @id;


Исправленная версия:

; WITH OkUsers AS (
    SELECT 
     u.* 
    FROM Users u 
     JOIN Friends f ON u.Id = f.SenderId OR u.Id = f.RecipientId 
    WHERE 
     f.Status = 'Ok' 
) 
SELECT TOP(20) 
    a.* 
    ,b.UserName as Sender 
    ,c.UserName as Receiver 
    ,b.Avatar as SenderPic 
FROM Events a 
    INNER JOIN OkUsers b ON a.SenderId = b.Id 
    INNER JOIN OkUsers c ON a.ReceiverId = c.Id 
WHERE 
    a.SenderId = @id 
    OR a.ReceiverId = @id; 
+1

+1 абсолютно - объединяя команду SQL, подобную этой, является ОГРОМНОЙ ГИПЕРНОЙ инъекцией SQL, ожидающей использования! –

+0

Я думаю, что у оригинала было дополнительное предложение WHERE в Friends.State = 'ok' (при условии, что столбец состояния определен в таблице друзей) –

+0

@Tom Carver Спасибо за подсказку. Я обновил инструкцию SQL. –

0

Я думаю, что может помочь:

--step[1] 
SELECT DISTINCT CASE 
WHEN a.Id = 1 THEN c.ID 
WHEN c.Id = 1 THEN a.Id 
ELSE 
0 
END AS ID 
INTO #OkUsers 
From Friends b INNER JOIN Users a 
ON b.SenderId = a.Id INNER JOIN Users c 
ON b.ReceiverId = c.Id 
WHERE (c.Id = @id OR a.Id = @id) AND State = 'Ok'; 

--step[2] 
SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic 
FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id 
INNER JOIN #OkUsers ON #OkUsers.ID = SenderId OR #OkUsers.ID = ReceiverId 
EXCEPT 
SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic 
FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id 
--INNER JOIN #OkUsers ON #OkUsers.ID = SenderId OR #OkUsers.ID = ReceiverId 
WHERE SenderId IN (SELECT ID FROM #OkUsers) 
    OR ReceiverId IN(SELECT ID FROM #OkUsers); 

DROP TABLE #OkUsers; 

таблицы Temp хорошо работать с очень большим объемом data.Otherwise вы можете использовать таблицу памяти.

+0

как я могу использовать это в своем коде! Кроме того, я выделил все идентификационные номера всем друзьям члена, а затем поместил их в переменную типа String, которая будет использоваться с предложением IN во втором запросе .. это хороший способ или что?? – Rawhi

+0

любой код sql, который дает вам конечный результат только в одной поездке в db, лучше, чем делать это с двумя раундами. Кроме того, получение данных с сервера sql в память и работа с ним - это более высокая производительность, чем все это с сервером sql, но это не всегда правильное правило, поскольку оно зависит от объема данных, емкости сервера приложений и загрузки пользователей ... и т. д. –

+0

Я даже не могу представить, как это можно было бы написать в одном заявлении sql !!! #OkUsers => SELECT => DROP – Rawhi

Смежные вопросы