Alright, let's to business ...
say I have a category (categoyid) '150 ', and would not bring anything that is in that category .....
It turns out that an article may be in multiple categories, and the more I block 150 in the category SELECT, it will still come to be linked to other categories ....
How do I, so that any item in the category '150 'is not sought in the SELECT even though he was also in another category than the '150' ...
Tables:
node
nodeid
contentid
url
publishdate
nodeinfo
nodeid
title
node_category
categoryid
nodeid
article
contentid
previewimage
=====================
I tried :
SELECT p.nodeid, p.contentid p.publishdate, p.url, c.categoryid, c.nodeid, a.previewimage, a.contentid, e.title FROM `node` AS p
INNER JOIN `nodecategory` AS c ON p.`nodeid` = c.`nodeid`
INNER JOIN `article` AS a ON p.`contentid` = a.`contentid`
INNER JOIN `nodeinfo` AS e ON p.`nodeid` = e.`nodeid`
WHERE c.`categoryid`
IN (73,74,77,105,71,70,72,76,100,80,79,78,81,108,145,146,82,142,83,97,153)
GROUP BY c.nodeid
ORDER BY p.`publishdate`
DESC LIMIT 4
I think you need a not-exists clause:
AND NOT EXISTS (
SELECT 1
FROM
`nodecategory` AS ic
WHERE
p.`nodeid` = ic.`nodeid`
AND ic.`categoryid` IN (150)
)
Here it is in your query, reformatted a bit:
SELECT
p.nodeid,
p.contentid,
p.publishdate,
p.url,
c.categoryid,
c.nodeid,
a.previewimage,
a.contentid,
e.title
FROM
`node` AS p
INNER JOIN `nodecategory` AS c ON p.`nodeid` = c.`nodeid`
INNER JOIN `article` AS a ON p.`contentid` = a.`contentid`
INNER JOIN `nodeinfo` AS e ON p.`nodeid` = e.`nodeid`
WHERE c.`categoryid`
IN (73,74,77,105,71,70,72,76,100,80,79,78,81,108,145,146,82,142,83,97,153)
AND NOT EXISTS (
SELECT 1
FROM
`nodecategory` AS ic
WHERE
p.`nodeid` = ic.`nodeid`
AND ic.`categoryid` IN (150)
)
GROUP BY c.nodeid
ORDER BY p.`publishdate`
DESC LIMIT 4
This should filter out nodes that are in one of the chosen categories, but are not also in those specified in the not-exists clause.
Related
I'm not sure how to make the following SQL query more efficient. Right now, the query is taking 8 - 12 seconds on a pretty fast server, but that's not close to fast enough for a Website when users are trying to load a page with this code on it. It's looking through tables with many rows, for instance the "Post" table has 717,873 rows. Basically, the query lists all Posts related to what the user is following (newest to oldest).
Is there a way to make it faster by only getting the last 20 results total based on PostTimeOrder?
Any help would be much appreciated or insight on anything that can be done to improve this situation. Thank you.
Here's the full SQL query (lots of nesting):
SELECT DISTINCT p.Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(p.PostCreationTime) AS PostTimeOrder
FROM Post p
WHERE (p.Id IN (SELECT pc.PostId
FROM PostCreator pc
WHERE (pc.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pc.UserId = '100')
))
OR (p.Id IN (SELECT pum.PostId
FROM PostUserMentions pum
WHERE (pum.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pum.UserId = '100')
))
OR (p.Id IN (SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100'))
))
OR (p.Id IN (SELECT psm.PostId
FROM PostSMentions psm
WHERE (psm.StockId IN (SELECT sf.StockId
FROM StockFollowing sf
WHERE sf.UserId = '100' ))
))
UNION ALL
SELECT DISTINCT p.Id AS Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(upe.PostEchoTime) AS PostTimeOrder
FROM Post p
INNER JOIN UserPostE upe
on p.Id = upe.PostId
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND (uf.FollowingId = '100' OR upe.UserId = '100'))
ORDER BY PostTimeOrder DESC;
Changing your p.ID in (...) predicates to existence predicates with correlated subqueries may help. Also since both halves of your union all query are pulling from the Post table and possibly returning nearly identical records you might be able to combine the two into one query by left outer joining to UserPostE and adding upe.PostID is not null as an OR condition in the WHERE clause. UserFollowing will still inner join to UPE. If you want the same Post record twice once with upe.PostEchoTime and once with p.PostCreationTime as the PostTimeOrder you'll need keep the UNION ALL
SELECT
DISTINCT -- <<=- May not be needed
p.Id
, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime
, p.Content AS Content
, p.Bu AS Bu
, p.Se AS Se
, UNIX_TIMESTAMP(coalesce( upe.PostEchoTime
, p.PostCreationTime)) AS PostTimeOrder
FROM Post p
LEFT JOIN UserPostE upe
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND
(uf.FollowingId = '100' OR
upe.UserId = '100'))
on p.Id = upe.PostId
WHERE upe.PostID is not null
or exists (SELECT 1
FROM PostCreator pc
WHERE pc.PostId = p.ID
and pc.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pc.UserID
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM PostUserMentions pum
WHERE pum.PostId = p.ID
and pum.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pum.UserId
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM SStreamPost ssp
WHERE ssp.PostId = p.ID
and exists (SELECT 1
FROM SStreamFollowing ssf
WHERE ssf.SStreamId = ssp.SStreamId
and ssf.UserId = '100')
)
OR exists (SELECT 1
FROM PostSMentions psm
WHERE psm.PostId = p.ID
and exists (SELECT
FROM StockFollowing sf
WHERE sf.StockId = psm.StockId
and sf.UserId = '100' )
)
ORDER BY PostTimeOrder DESC
The from section could alternatively be rewritten to also use an existence clause with a correlated sub query:
FROM Post p
LEFT JOIN UserPostE upe
on p.Id = upe.PostId
and ( upe.UserId = '100'
or exists (select 1
from UserFollowing uf
where uf.FollwedID = upe.UserID
and uf.FollowingId = '100'))
Turn IN ( SELECT ... ) into a JOIN .. ON ... (see below)
Turn OR into UNION (see below)
Some the tables are many:many mappings? Such as SStreamFollowing? Follow the tips in http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
Example of IN:
SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (
SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100' ))
-->
SELECT ssp.PostId
FROM SStreamPost ssp
JOIN SStreamFollowing ssf ON ssp.SStreamId = ssf.SStreamId
WHERE ssf.UserId = '100'
The big WHERE with all the INs becomes something like
JOIN ( ( SELECT pc.PostId AS id ... )
UNION ( SELECT pum.PostId ... )
UNION ( SELECT ssp.PostId ... )
UNION ( SELECT psm.PostId ... ) )
Get what you can done of that those suggestions, then come back for more advice if you still need it. And bring SHOW CREATE TABLE with you.
ModuleUserPermission is my main table to query from where i get module ids for a particular user and in module table there i get menu ids to query menu table here is issue that module table consist of only end point menu ids and i want all of its parents as well
select *
from [ModuleUserPermission] mup
inner join Module ml on ml.Id = mup.Module_Id
--inner join Menu m on m.Id = ml.Menu_Id and m.IsActive = 1
where (NULLIF(#AspNetUsers_Id,'') IS NULL OR mup.AspNetUsers_Id = #AspNetUsers_Id)
SOLUTION:
this is what I did could we do it in proper way ?
DECLARE #TblTemp TABLE(
Id int,
ParentId int,
Name nvarchar(max),
Url nvarchar(max) NULL,
SortOrder int,
IconClass nvarchar(max) NULL,
IsActive bit
);
;With temp as (
select distinct m.*
from [ModuleUserPermission] mup
inner join Module ml on ml.Id = mup.Module_Id
inner join Menu m on m.Id = ml.Menu_Id and m.IsActive = 1
where (NULLIF(#AspNetUsers_Id,'') IS NULL OR mup.AspNetUsers_Id = #AspNetUsers_Id)
union all
select m.*
from Menu m
inner join temp r on r.ParentId = m.Id
where m.IsActive = 1
)
INSERT INTO #TblTemp select * from temp
;With relation (Id, IconClass,SortOrder, ParentId, Name,Url,IsActive, [Level], [OrderSequence])
as
(
select distinct m.Id, m.IconClass,m.SortOrder, m.ParentId, m.Name,ISNULL(m.Url,'') Url,m.IsActive, 1, cast(m.Id as varchar(20))
from #TblTemp m where m.ParentId = 0
union all
select p.Id, p.IconClass,p.SortOrder, p.ParentId,p.Name,p.Url,p.IsActive, r.[Level]+1, cast(r.orderSequence + '_' + cast(p.Id as varchar) as varchar(20))
from #TblTemp p
inner join relation r on p.ParentId = r.Id
)
select * from relation order by OrderSequence
Since the relationship between top level menu items and lower level items is described in the ParentId column, you need to join your Menu table with itself, like this:
select coalesce(m2.Id, m1.Id), coalesce(m2.Name, m1.Name)
from [ModuleUserPermission] mup
join Module ml on ml.Id = mup.Module_Id
join Menu m on m.Id = ml.Menu_Id and m.IsActive = 1
left join Menu m2 on m.Id = m2.ParentId and m2.IsActive = 1
where (NULLIF(#AspNetUsers_Id,'') IS NULL OR mup.AspNetUsers_Id = #AspNetUsers_Id)
The left join is because top level items won't join with any other item, so with a inner join you would lose them. This way you preserve them but with nulls, hence the coalesces
I'm struggling with an problem to make a query of the following:
I have an table called Article_Statuses (and the main table Articles, with ArticleID as p.key) and has the following structure
ID, ArticleID, Status, Status_Date, Category
In this table I collect all the statuses of the articles (ArticleID) per category (which are predefined), the highest ID per category is the latest status of that category, herewith some data:
1, BB0001, LFS, 15-01-2015, LIC
2, BB0001, LFA, 19-01-2015, LIC
3, BB0001, SA, 10-01-2015, FIS
4, BB0001, CA, 19-01-2015, FIS
5, BB0002, LFS, 10-01-2015, LIC
6, BB0002, LFA, 11-01-2015, LIC
7, BB0003, CA, 19-01-2015, FIS
I want to make a query with the following result:
ArticleID, Status LIC, Status_Date LIC, Status FIS, Status_Date FIS
BB0001, LFA, 19-01-2015, CA, 19-01-2015
BB0002, LFA, 11-01-2015, ,
BB0003, , , CA, 19-01-2015
I found the following solution which works for only one category, I'm stuck with adding the other categories...
SELECT `a`.`ArticleID`, `b`.`Status_Date` AS `LIC_Date`, `b`.`Status` AS `LIC_Status`
FROM `Articles` `a`
INNER JOIN `Article_Statuses` `b` ON `a`.`ArticleID` = `b`.`ArticleID`
INNER JOIN ( SELECT `ArticleID`, MAX( `ID` ) `MAXID`
FROM `Article_Statuses`
WHERE `Category` = 'LIC' GROUP BY `ArticleID` ) `c`
ON `b`.`ArticleID` = `c`.`ArticleID` AND `b`.`ID` = `c`.`MAXID`
WHERE `a`.`Partner` = 10
GROUP BY `a`.`ArticleID`
ORDER BY `a`.`ArticleID` ASC
What is the meaning of "Partner" in your query? You didn't mentioned it anywhere earlier so I'm guessing it's not important.
How many different categories do you have? Just two or more? I'm asking because returning data in such a way is far for being fast and optimal.
It would be something like:
SELECT
a.ArticleID,
b.Status_Date AS LIC_Date, b.Status AS LIC_Status,
d.Status_Date AS FIS_Date, d.Status AS FIS_Status
FROM Articles AS a
INNER JOIN Article_Statuses AS b ON a.ArticleID = b.ArticleID
INNER JOIN (
SELECT ArticleID, MAX( ID ) AS ID
FROM Article_Statuses
WHERE Category = 'LIC' GROUP BY ArticleID
) AS c ON b.ArticleID = c.ArticleID AND b.ID = c.ID
INNER JOIN Article_Statuses AS d ON a.ArticleID = d.ArticleID
INNER JOIN (
SELECT ArticleID, MAX( ID ) AS ID
FROM Article_Statuses
WHERE Category = 'FIS' GROUP BY ArticleID
) AS e ON d.ArticleID = e.ArticleID AND d.ID = e.ID
WHERE a.Partner = 10
ORDER BY a.ArticleID ASC
Basically you repeat joins just with different aliased - I used "d" and "e" but it's better to use something meaningful like "LIC_category" instead of just "b".
You also should use left join instead of inner join if some categories can be empty as in your example.
This is the query which returns desired result:
select a.articleid,
b.status_date as LIC_Date, b.status as LIC_Status,
c.status_date as FIS_Date, c.status as FIS_Status
from Articles a
left join Article_Statuses b on b.ArticleID =a.articleid and
b.id = (select max(id) from Article_Statuses ast
where ast.articleid=a.articleid and ast.category='LIC')
left join Article_Statuses c on c.ArticleID =a.articleid and
c.id = (select max(id) from Article_Statuses ast
where ast.articleid=c.articleid and ast.category='FIS')
order by a.articleid
I used left joins because not for every article both categories are present.
I have three tables:
cp_projeto (id, nome...)
cp_habilidade_projeto (id, id_projeto)
cp_habilidade (id, nome...)
I need all projects with all cp_habilidade where cp_projeto have one cp_habilidade. My actual query:
SELECT
p.id as id_projeto,
p.nome as nome_projeto,
p.id_tipo_projeto,
p.dhPostagem,
cp_habilidade_projeto.id as id_habilidade_projeto,
cp_habilidade.nome as nome_habilidade
FROM (
SELECT * FROM cp_projeto
WHERE (id_status_projeto = 2)
ORDER BY dhPostagem DESC LIMIT 0, 10
) AS p
inner JOIN cp_habilidade_projeto ON (cp_habilidade_projeto.id_projeto = p.id)
inner JOIN cp_habilidade ON (cp_habilidade.id = cp_habilidade_projeto.id_habilidade)
JOIN cp_sub_categoria ON (cp_sub_categoria.id = p.id_sub_categoria)
WHERE (
p.nome like '%CSS%'
OR cp_habilidade.nome like '%CSS%'
)
This returns only cp_habilidade.nome = %CSS%, I need it all.
Thanks!
SELECT
p.id as id_projeto,
p.nome as nome_projeto,
p.id_tipo_projeto,
p.dhPostagem,
hp.id as id_habilidade_projeto,
h.nome as nome_habilidade
FROM cp_projecto p
JOIN cp_habilidade_projeto hp ON p.id = hp.id_projeto
JOIN cp_habilidade h ON h.id = hp.id_habilidade
WHERE p.id IN ( SELECT cp_habilidade_projeto.id_projeto
FROM cp_habilidade
JOIN cp_habilidade_projeto ON cp_habilidade.id = cp_habilidade_projeto.id_habilidade
WHERE cp_habilidade.nome LIKE '%CSS%' )
I have been trying to get this query to work but I am stumbed right now.
Problem is on the JOIN with GROUP_CONCAT in it. I just can't figure how to get it working.
What I want is to get buntch of data from RFQs and joining Customers, etc. to it and everything was fine until I had to change Suppliers field so that it could have multiple suplliers per one RFQs row. I created new tables RFQsSuppliers where I combine Supplier.ID's and RFQs.ID's and I have table Suppliers that contains the names and other stuff.
I want to get Suppliers to have all suppliers separated with ','.
My Query:
$result = mysql_query("SELECT Pullero.DateAdded as DateAdded,
Customers.Name as customer,
Pullero.ID as RFQID,
Ships.Name as ship,
Pullero.CustomerRef as CustomerRef,
Contacts.FirstName as contactF,
Contacts.LastName as contactL,
Contacts.Email as contactE,
Users.tunnus as handler,
RFQStatus.Name as status,
Pullero.Description as RFQDescription,
Pullero.LastEdited as LastEdit
FROM RFQs Pullero
JOIN (SELECT RFQs.ID,
GROUP_CONCAT(Supplier.Name) AS Suppliers
FROM RFQs
LEFT JOIN RFQsSuppliers ON RFQs.ID = RFQsSuppliers.RFQID
JOIN Suppliers ON RFQsSuppliers.SupplierID = Suppliers.ID
GROUP BY RFQs.ID)
RFQsSuppliers ON Pullero.ID = RFQsSuppliers.RFQID
LEFT JOIN Ships ON RFQ.ShipID=Ships.ID
LEFT JOIN Contacts ON RFQ.ContactID=Contacts.ID
LEFT JOIN Customers ON RFQ.CustomerID=Customers.idCustomers
LEFT JOIN Users ON RFQ.PriJobHandler=Users.id
LEFT JOIN RFQStatus ON RFQ.StatusID=RFQStatus.ID
WHERE RFQs.LastEdited > '$lastedited'
ORDER BY RFQs.LastEdited ASC
") or die(mysql_error());
At the moment, error is :Unknown column 'Supplier.Name' in 'field list'
EDIT
Below is some expample of my Table desing:
RFQs
ID | DateAdded | CustomerID | ShipID | LastEdited | StatusID ...
/* -------------------------------------- */
Suppliers
ID | Name | CountryID
1 Sup1 2
2 Sup2 5
3 Sup3 3
4 Sup4 3
/* -------------------------------------- */
RFQsSuppliers
ID | RFQID | SupplierID
1 1 4
2 2 3
3 56 3
4 4 3
5 39 1
6 56 1
7 4 4
I tried to get only the suppliers with following query:
$result = mysql_query("SELECT Suppliers.Name as Suppliers
FROM RFQs
LEFT JOIN RFQsSuppliers ON RFQs.ID=RFQsSuppliers.SupplierID
LEFT JOIN Suppliers ON RFQsSuppliers.SupplierID=Suppliers.ID
GROUP BY RFQs.ID
") or die(mysql_error());
But print_r on each row returns only following:
Array ( [Suppliers] => Sup1,Sup1 ) Array ( [Suppliers] => ) Array ( [Suppliers] => Sup4,Sup4 ) Array ( [Suppliers] => ) Array ( [Suppliers] => ) Array ( [Suppliers] => )
Any ideas?
JOIN (
SELECT RFQs.ID,
GROUP_CONCAT(Supplier**s**.Name) AS Suppliers
FROM RFQs
LEFT JOIN RFQsSuppliers ON RFQs.ID = RFQsSuppliers.RFQID
JOIN Suppliers ON RFQsSuppliers.SupplierID = Suppliers.ID
GROUP BY RFQs.ID
) RFQsSuppliers
Try that
I believe you missed an 's' in your GROUP_CONCAT table name as you had it as Supplier.Name instead of Suppliers.name as per the table
Edit
Additionally you are referring to RFQs.LastEdited in WHERE and ORDER BY clauses however you aliased table RFQs to be named Pullero, so those will need changing to Pullero.LastEdited
Edited edit Reformatted to use JOINs instead of SUBQUERY
SELECT
Pullero.DateAdded as DateAdded,
Customers.Name as customer,
Pullero.ID as RFQID,
GROUP_CONCAT(Suppliers.Name) AS Suppliers,
Ships.Name as ship,
Pullero.CustomerRef as CustomerRef,
Contacts.FirstName as contactF,
Contacts.LastName as contactL,
Contacts.Email as contactE,
Users.tunnus as handler,
RFQStatus.Name as status,
Pullero.Description as RFQDescription,
Pullero.LastEdited as LastEdit
FROM RFQs AS Pullero
LEFT JOIN RFQsSuppliers ON RFQsSuppliers.RFQID = Pullero.ID
LEFT JOIN Suppliers ON RFQSuppliers.SupplierID = Suppliers.ID
LEFT JOIN Ships ON RFQ.ShipID=Ships.ID
LEFT JOIN Contacts ON RFQ.ContactID=Contacts.ID
LEFT JOIN Customers ON RFQ.CustomerID=Customers.idCustomers
LEFT JOIN Users ON RFQ.PriJobHandler=Users.id
LEFT JOIN RFQStatus ON RFQ.StatusID=RFQStatus.ID
WHERE Pullero.LastEdited > '$lastedited'
ORDER BY Pullero.LastEdited ASC
Or for an example using original subquery, the RFQs link seems superfulous so I've adjusted it + have added the Suppliers list into the output
$result = mysql_query("SELECT Pullero.DateAdded as DateAdded,
RFQsSuppliers.Suppliers,
Customers.Name as customer,
Pullero.ID as RFQID,
Ships.Name as ship,
Pullero.CustomerRef as CustomerRef,
Contacts.FirstName as contactF,
Contacts.LastName as contactL,
Contacts.Email as contactE,
Users.tunnus as handler,
RFQStatus.Name as status,
Pullero.Description as RFQDescription,
Pullero.LastEdited as LastEdit
FROM RFQs Pullero
JOIN (
SELECT RFQsSuppliers.RFQID,
GROUP_CONCAT(Suppliers.Name) AS Suppliers
FROM RFQsSuppliers.RFQID
JOIN Suppliers ON RFQsSuppliers.SupplierID = Suppliers.ID
GROUP BY RFQsSuppliers.RFQID
) AS RFQsSuppliers ON Pullero.ID = RFQsSuppliers.RFQID
LEFT JOIN Ships ON RFQ.ShipID=Ships.ID
LEFT JOIN Contacts ON RFQ.ContactID=Contacts.ID
LEFT JOIN Customers ON RFQ.CustomerID=Customers.idCustomers
LEFT JOIN Users ON RFQ.PriJobHandler=Users.id
LEFT JOIN RFQStatus ON RFQ.StatusID=RFQStatus.ID
WHERE Pullero.LastEdited > '$lastedited'
ORDER BY Pullero.LastEdited ASC
") or die(mysql_error());
EDIT Updated query for second part of question
$result = mysql_query("SELECT RFQs.ID, GROUP_CONCAT(Suppliers.Name) as Suppliers
FROM RFQs
LEFT JOIN RFQsSuppliers ON RFQs.ID=RFQsSuppliers.RFQID
LEFT JOIN Suppliers ON RFQsSuppliers.SupplierID=Suppliers.ID
GROUP BY RFQs.ID
") or die(mysql_error());
You're referencing the column Supplier.Name, but the table join is on a table called Suppliers, plural.
(SELECT RFQs.ID,
/* Should be plural Suppliers.Name here... */
GROUP_CONCAT(Suppliers.Name) AS Suppliers
FROM RFQs
LEFT JOIN RFQsSuppliers ON RFQs.ID = RFQsSuppliers.RFQID
JOIN Suppliers ON RFQsSuppliers.SupplierID = Suppliers.ID
GROUP BY RFQs.ID)
Later, in your final WHERE clause, you reference RFQs, however you have aliased that table as Pullero:
FROM RFQs Pullero
Change the WHERE clause to use
WHERE Pullero.LastEdited > '$lastedited'
ORDER BY Pullero.LastEdited ASC