I am trying to build a system, which has threads and posts. I am trying to fetch a thread that is the most popular (the user can click "like" button to make it more popular) and has most posts. The problem is to order the results by most posts..and then by liked posts.
So for example, if I have a thread with 300 posts, and 200 likes.. while another thread has got 300 likes and 201 likes..I want the second post to be selected..
Table structure in a nutshell:
topic:
--------
topic_id
liked
comment:
-------
comment_id
topic_id
Here is my stored procedure so far:
dbo.Trends
AS
SELECT TOP 1 title, COUNT(com.topic_id), COUNT(topc.user_id_liked)
FROM comment AS com
INNER JOIN topic AS topc ON com.topic_id=topc.topic_id
GROUP BY com.topic_id, topc.user_id_liked,title
ORDER BY COUNT(com.topic_id), COUNT(topc.user_id_liked) DESC
I am not sure if I am right, or will I have to result to control flow logic. I placed the topic_id from the topic table before topic liked column in the order statement..hoping the selecting/ordering of the topic_id will take precendence.
UPDATED: query updated.
I don't really know that you want. But maybe this will help:
;WITH CTE
AS
(
SELECT
COUNT(com.topic_id) OVER(PARTITION BY topc.liked) AS topicCount,
COUNT(com.liked) OVER(PARTITION BY topc.topic_id) AS likedCount,
title
FROM
commnet AS com
INNER JOIN topic AS topc
ON com.topic_id=topc.topic_id
)
SELECT TOP 1
CTE.title,
CTE.topicCount,
CTE.likedCount
FROM
CTE
ORDER BY
topicCount,
likedCount
EDIT
The differences between the GROUP BY and PARTITION BY is that PARTITION BY is an inline GROUP BY so this will not affect the number of rows. I like to use that in a CTE that is a inline view. Makes it clearer and you separate the different steps you want to do. If you remove the TOP 1 you will see what I mean.
Related
So I currently have a database that keeps tracks of projects, project updates, and the update dates. I have a form that with a subform that displays the project name and the most recent update made to said project. It was brought to my attention however, that the most recent update to a project does not display correctly. Ex: shows the update date of 4/6/2017 but the actual update text is from 3/16/2017.
Doing some spot research, I then learned that Access does not store records in any particular order, and that the Last function does not actually give you the last record.
I am currently scouring google to find a solution but to no avail as of yet and have turned here in hopes of a solution or idea. Thank you for any insight you can provide in advance!
Other details:
tblProjects has fields
ID
Owner
Category_ID
Project_Name
Description
Resolution_Date
Priority
Resolution_Category_ID
tblUpdates has these fields:
ID
Project_ID
Update_Date
Update
there is no built-in Last function that I am aware of in Access or VBA, where exactly are you seeing that used?
if your sub-form is bound directly to tblUpdates, then you ought to be able to just sort the sub-form in descending order based on either ID or Update_date.
if you have query joining the two tables, and are only trying to get a single row returned from tblUpdates, then this would do that, assuming the ID column in tblUpdates is an autonumber. if not, just replace ORDER BY ID with ORDER BY Update_Date Desc
SELECT a.*,
(SELECT TOP 1 Update FROM tblUpdates b WHERE a.ID = b.PROJECT_ID ORDER BY ID DESC ) AS last_update
FROM tblProjects AS a;
We are attempting to relate GL transactions GeneralJournalAccountEntry with their appropriate Project Category Id LedgerJournalTrans_Project, but are having a very difficult time relating the two tables.
We can get there by this route:
GeneralJournalAccountEntry.GeneralJournalEntry = GeneralJournalEntry.RecId (Many to 1)
GeneralJournalEntry.SubLedgerVoucher = LedgerJournalTrans.Voucher (1 to Many)
LedgerJournalTrans.RecId = LedgerJournalTrans_Project.RefRecId (1 to 1)
But the individual leg of the transaction gets lost in the Many to 1 and 1 to Many relationships. We understand the tables are from different "modules", but are hoping there is some way to connect the two without depending on something messy like transaction amount.
Is this possible, or is there another way to accomplish our goal?
There is not a one-to-one relationship.
The closest thing would be to use Voucher and TransDate on LedgerJournalTrans to fetch ledger transactions.
See this post.
There is a white paper describing the AX 2012 ledger posting framework.
I'm not certain yet that I have this completely figured out, but I think this can be used to create a similar link. I'm trying to link the generaljournalaccountentry line items to the inventjounrnaltrans line items. This should provide the link between the two tables based on the voucher and line item number and give me the itemid. I would think there would necessarily be a similar link to the project because of the ability to navigate that way in the front end application. It might also be helpful to trace the SQL query when performing the action in the front end.
SELECT itp.[PARTITION]
, itp.[DATAAREAID]
, itp.[TRANSDATE]
, itp.[VOUCHER]
, itp.[ITEMID]
, itojt.[INVENTJOURNALLINENUM]
, MAX(ito.[REFERENCEID]) AS [REFERENCEID]
FROM [dbo].[INVENTTRANSPOSTING] itp WITH(NOLOCK)
INNER JOIN [dbo].[INVENTTRANSORIGIN] ito WITH(NOLOCK)
ON ito.[RECID] = itp.[INVENTTRANSORIGIN]
INNER JOIN [dbo].[INVENTTRANSORIGINJOURNALTRANS] itojt WITH(NOLOCK)
ON itojt.[INVENTTRANSORIGIN] = ito.[RECID]
WHERE (itp.[INVENTTRANSPOSTINGTYPE] = 1 OR itp.[INVENTTRANSPOSTINGTYPE] = 0)
AND itp.[ISPOSTED] = 1
GROUP BY itp.[PARTITION]
, itp.[DATAAREAID]
, itp.[TRANSDATE]
, itp.[VOUCHER]
, itp.[ITEMID]
, itojt.[INVENTJOURNALLINENUM]
I am trying to get data from one table which is in varchar form and pass the same to other query which has same field as int.
Table Article with following fields
(ArticleID int, ArticleTitle nvarchar(200), ArticleDesc nvarchar(MAX))
Sample data
1 Title1 Desc1
2 Title2 Desc2
3 Title3 Desc3
I have another Table called Banner which has banner related to Articles
(BannerID int, BannerName nvarchar(200), BannerPath nvarchar(MAX), ArticleID varchar(200))
Sample Data
**BannerID BannerName BannerFile ArticleID**
100 Banner1 BannerPath1 '1','3','5'
101 Banner2 BannerPath2 '2','3','5'
102 Banner3 BannerPath3 '8','3','5'
103 Banner4 BannerPath4 '10','30','5','2','3','5'
Sample Query
SELECT ArticleTitle
FROM Article
WHERE CAST(ArticleID AS varchar(200)) IN (
SELECT ArticleID FROM Banner WHERE BannerID = 2
)
In my actual project i have multiple fields in banner table so that i can assign banner article, writer, Category, Pages..
For this reason i decided to store ArticleID or WriteID or CatID as single field in this format'10','30','5','2','3','5'
I change my structure then i may end up create hundreds of records for one banner and one banner can be assigned to any one of this article, writer, Category, Pages
Query below return zero rows may be my casting is creating problem I would appreciate how i can get arounds this without changing my database structure
SELECT ArticleTitle FROM Article WHERE CAST(ArticleID AS varchar(200)) IN (SELECT ArticleID FROM Banner WHERE BannerID = 2)
UPDATED:
No offense to any one i have decided to stick to my design as the question i had asked was for backed reporting section of the website which won't be used to often. I can be wrong regarding not normalizing the tables ...
My actual scenario Suppose users visit url
`abc.com/article/article.aspx?articleID=30&CatID=10&PageID=3&writerID=3`
Based on this url i can run four queries with UNION to get the required banner off-course i have to decide on banner precedence so i will do it like this
`SELECT BannerName, BannerImage FROM Banner WHERE ArticleID LIKE '%''30''%'`
UNION ALL
`SELECT BannerName, BannerImage FROM Banner WHERE CategoryID LIKE '%''10''%'`
UNION ALL
`Another query .......`
If i do it this way then query will have to look for banners in single table with few rows But if i normalize table based on JW which is good way of doing it may result in 30-40 rows for each banner in different table which may effect performance as i have to add new banner for new articles (for new magazine issues).
I know i am breaking every law of normalizing but i am afraid i have to do it for performance as i may end up having 2000 rows for every 100 banners & this will grow with time.
Updated Again
I hope this image will give you an over view of what i am trying to do
If i do it this way then i only need 1 row per banner & if i further normalize and create more table then i might end up having several row for one banner for example
Taking above image sample from banner table then my first banner will have 27 Rows
Second Banner 11 Rows
Thirds Banner 14 rows.
In order to avoid this i thought of to store multiple articleID, IssueID, PageID .... in their respected fields. This approach might be dirty but it is working.
I Definitely had some -ve feedback which from their point of view is understandable.. Since i have provided further details is my approach totally unprofessional or it is fine keeping in mind that website might have very good traffic & this approach may be faster.
It is a very bad design when you have saved comma separated values in a column when these values will be used in searching of records.
You need to properly normalize and restructure the table into 3-table design because I can see a Many-to-Many relationship on Article and Banner.
Suggested Schema design:
Article Table
ArticleID (PK)
ArticleTitle
ArticleDesc
Banner Table
BannerID (PK)
BannerName
BannerPath
Article_Banner Table
ArticleID (FK) (Also a compound PK with BannerID)
BannerID (FK)
and by this design you can simply query your records like:
SELECT a.*
FROM Article a
INNER JOIN Article_Banner b
ON a.ArticleID = b.ArticleID
WHERE b.BannerID = 2
advantages of the structure:
can easily create query statements
can take advantage of the indexes defined
etc..
In additio to John Woo's excellent answer, I will try to answer the question "Why doesn't the query return any results".
I'm going to leave aside the WHERE b.BannerID = 2 clause, which is obviously not met by any of the sample records.
The main issue with the query is the IN clause. IN will tell you whether an item is found in a set of items. What you are expecting it to do is iterate through a set of sets and tell you whether the item is found.
To illustrate this, here are two simplified queries:
-- this will print 0
if '1' in ('''1'',''3'',''5''')
print 1
else
print 0
-- this will print 1
if '1' in ('1', '3', '5')
print 1
else
print 0
The main point is that IN is a set-based operation, not a string function that will find a substring.
One possible solution to your problem would be to use CHARINDEX to perform the substring detection:
select ArticleTitle
from Article a
join Banner b
on charindex(CAST(a.ArticleID AS varchar(200)), b.ArticleID) > 0
This version is incorrect, because searching for the id '1' will also match values like '11','12'.
In order to get correct results, you could end up with a query similar to this (in order to make sure you only match on values between asterisks):
select ArticleTitle
from Article a
join Banner b
on charindex('''' + CAST(a.ArticleID AS varchar(200)) + '''', b.ArticleID) > 0
SQLFiddle: http://www.sqlfiddle.com/#!3/2ee3c/23
This query, however, has two big disadvantages:
it gets awfully slow for relatively big tables, as it cannot use any indexes and needs to scan the Banner table for each row in Article
the code got a little bit more complex and the more functionality you'll add to it, the harder it will get to reason about it, resulting in maintainability problems.
These two problems are smells that you are doing something wrong. Following JW's solution will get rid of the two problems.
Fully agree the above example is bad and not the correct way for what he is doing. However the root error message issue still exist and is a problem under some conditions.
My situation is working with a table to hold some custom form field element data. Without laying out the entire structure I’ll just lay out what is needed to show and reproduce the issue. I can also confirm the issue resolves around the IsNumeric in this case. Combined with the SubQueries as well. The sample holds two items, item name simulating the custom field element/type and the field value. Some are names, and some are minutes of labor. Could be weights, temps, distances, whatever, it’s customer definable extra data.
Create Table dboSample (cKey VarChar(20), cData VarChar(50))
Insert Into dboSample (cKey, cData) Values ('name', 'Jim')
Insert Into dboSample (cKey, cData) Values ('name', 'Bob')
Insert Into dboSample (cKey, cData) Values ('labortime', '60')
Insert Into dboSample (cKey, cData) Values ('labortime', '00')
Insert Into dboSample (cKey, cData) Values ('labortime', '15')
Select * From (Select * From dboSample Where IsNumeric(cData) = 1) As dboSampleSub Where Cast(cData As Int) > 0
Resulting in an error “Conversion failed when converting the varchar value 'Jim' to data type int.”
The lower nested query has a where clause limiting returned rows to only included numeric based data. However the cast in the higher level is clearly seeing rows not included in the sub query return. It is in fact seeing and processing data of the lower nested query. Cannot locate an Select OPTION flags to prevent this.
I'm developing a system like SO (completely different topic) and replies and comments are alike with the system we see everyday on StackOverflow.
My question is, I'm loading the question with a Stored PROC, loading replies with another Stored PROC and now I'm adding comment system. Do I need to fetch the comments 1 by 1 for each of the replies on topic?
This means that if I have my page size set to 20 replies, I'll be doing 22 database operations which is more than I was thinking.
I don't think I need to add my database diagram for this question but still here it is:
Questions
-----------
QUESTION_ID
USER_ID
QUESTION_TEXT
DATE
REPLIES
-----------
REPLY_ID
QUESTION_ID
USER_ID
REPLY_TEXT
DATE
COMMENTS
------------
REPLY_ID (fk replies)
USER_ID
TEXT
DATE
You should get all your comments at once.
Then make DataViews from the result with a filter for each reply and bind to that DataView. You could also use linq to entities and just filter out new sets on each bind. Here is a basic pseudo code example:
Get all comments for all replies to question
Bind replies
Implement the OnDataBinding for the reply control that will display the comments
In the OnDataBinding add a filter to the result set for the comments with the same reply ID
Bind the filtered list of comments to the display control for comments
This should work and I have implement the same scenario for similar types of data structures.
Pabuc,
For your initial Question, why not get all the results using a single Query for the given question / reply ?
select reply_text, user_id
from REPLIES
order by DATE asc
Also, as you pointed out, except for the minor differences, the question and answer have almost the same attributes as that of a post.
Wouldn't a model like the one below make more sense? The Question and Answer are both "posts" with the only difference being an answer has the question as the parent and the question has no parent.
Create table post -- question/reply (
post_id number,
parent_post_id number, -- will be null if it is the question, will have the question id
-- if it is a reply to a question
post_text varchar2(4000),
user_id number,
post_date date);
-self referential foreign key
Alter table post
add constraint foreign key (parent_post_id) references post(post_id);
--comments to all posts (questions/replies).
create table comments(
comment_id number,
post_id number,
comment_txt varchar2(140),
comment_user_id number,
comment_date date
);
alter table comments add constraint fk_comments_post
foreign key (post_id) references post(post_id).
-- for a given Question (post) id, you can get all the replies and posts using...
select replies.*,
comments.*
from posts replies,
comments
where replies.parent_id = :Question_id --input
and comments.post_id = replies.post_id
You might have to add an order by clause to get the results based on points, updated_timestamp or any other attribute as needed.
This is a followup on the question:
ASP.NET next/previous buttons to display single row in a form
As it says on the page above, theres a previous/next button on the page, that retrieves a single row one at a time.
Totally there's ~500,000 rows.
When I "page" through each subscribtion number, the form gets filled with subscriber details. What approach should I use on the SQL server?
Using the ROW_NUMBER() function seems a bit overkill as it has to number all ~500.000 rows (I guess?), so what other possible solutions are there?
Thanks in advance!
ROW_NUMBER() is probably your best choice.
From this MSDN article: http://msdn.microsoft.com/en-us/library/ms186734.aspx
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT *
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
And just subsititute 50 and 60 with a parameter for the row number you want.
Tommy, if your user has time to page through 500,000 rows at one page per row, then he/she is unique.
I guess what I am saying here is that you may be able to provide a better UX. When - Too many pages? Build a search feature.
There are two potential workarounds (for this purpose, using a start of 201, pages of 100):
SQL
SELECT TOP 100 * FROM MyTable WHERE ID > 200 ORDER BY ID
LINQ to SQL
var MyRows = (from t in db.Table
order by t.ID ascending
select t).Skip(200).Take(100)
If your ID field has a clustered index, use the former. If not, both of these will take the same amount of time (LINQ returns 500,000 rows, then skips, then takes).
If you're sorting by something that's NOT ID and you have it indexed, use ROW_NUMBER().
Edit: Because the OP isn't sorting by ID, the only solution is ROW_NUMBER(), which is the clause that I put at the end there.
In this case, the table isn't indexed, so please see here for ideas on how to index to improve query performance.