SortBy for one-to-many relationship - sql-server-2005

I have a two tables which are linked by a one-to-many relationship. Now I need to sort the rows based on the key which I have in my first table.
For Ex
TeacherID StudentID
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
2 9
2 10
2 11
2 12
If I sort the Rows based on by teacherID, the student id's are changing for each and every execution.
In the result set the studentID are changing in the random order. Now I need the studentID's not to be changed.
Is there anything I can do, to solve this problem without using sort by the studentID column.

You can sort on both.
ORDER BY
TeacherID, StudentID
Selecting data from any database engine without specifying an ORDER BY doesn't guarantee any order at all.

Related

Combining related organisation records in SQL where there is a Parent-Child relationship between organisations

I am trying to build a table of data for use in Yellowfin BI reporting. One limitation of this is that no temporary tables can be created and then dropped in the database. I am pulling the data from an existing database, which i have no control over. I can only use SQL to query the existing data.
There are two tables in the source database i need to work with. I've simplified them for clarity. The first contains organisations. It has an ORG_ID column which contains a unique ID for each organisation and a PARENT_ORG_ID column indicating which organisation is the Parent Company of others in the list:
ORG_ID PARENT_ORG_ID
1 Null
2 1
3 5
4 5
5 Null
6 1
Using the table above i can see that there are the following relationships between organisations:
ORG_ID RELATED_ORGANISATIONS
1 2 and 6
2 1 and 6
3 5 and 4
4 5 and 3
5 4 and 3
6 1 and 2
I'm not sure the best way to represent these connections in a query as i need to use these relationships with a second table.
The second table i have is a list of organisations and money owed:
ORG_ID MONEY_OWED
1 5
2 10
3 0
4 15
5 20
6 5
What i need to achieve is a table that i can search for any single ORG_ID, and see the combined data for that Organisation and all related Organisations. In the case of my example, this could be a results table something like this:
ORG_ID MONEY_OWED_BY_ALL_RELATED_ORGS
1 20
2 20
3 35
4 35
5 35
6 20
I'm thinking i should use a CTE to handle the relationships between organisations but i can't get my head around it.
Any help would be greatly appreciated!
For your particular example, you can use:
select o.*,
sum(mo.money_owed) over (partition by coalesce(o.parent_org_id, o.org_id)) as parent_owed
from organizations o left join
money_owed mo
on mo.org_id = o.org_id;
This works because your organizations are only one level deep -- which is consistent with your sample data.

Querying duplicates table into related sets

We have a process that creates a table of duplicate records based on some arbitrary rules (details not relevant).
Every record gets checked against all other records and if a suspected duplicate is found both it and the duplicate are stored in a dupes table to be manually reviewed.
This results in a table something like this:
dupId, originalId, duplicateId
1 1 2
2 1 3
3 1 4
4 2 3
5 2 4
6 3 4
7 5 6
8 5 7
9 6 7
10 8 9
You can see here record #1 has 3 other records it is similar to (#2,#3 and #4) and they are each similar to each other.
Record #5 has 2 duplicates (#6 and #7) and record #8 has only 1 (#9).
I want to query the duplicates into sets, so my results would look something like this:
setId recordId
1 1
1 2
1 3
1 4
2 5
2 6
2 7
3 8
3 9
But I am too old/slow/tired/rubbish and a bit out of my depth here.
Currently, when checking for duplicates if the record pairing is already in the table we don't insert it twice (i.e. you don't see both sides of the duplicate pairing) but can easily do so if it makes the querying simpler.
Any advice much appreciated!
Duplicates seems to be transitive, so you have all pairs. That is, the "original" id has the information you need.
But it is not included in the duplicates and you want that. So:
select dense_rank() over (order by originalid) as setid, duplicateid
from ((select originalid, duplicateid
from t
where not exists (select 1 from t t2 where t.originalid = t2.duplicateid)
) union all
(select distinct originalid, originalid
from t
where not exists (select 1 from t t2 where t.originalid = t2.duplicateid)
)
) i
order by setid;

SQL Calculations With Multi-Group Affiliations

I'm attempting to have a function or view that is able to calculate and roll up various counts while being able to search on a many to many affiliation.
Here is an example data set:
Invoice Table:
InvoiceID LocationID StatusID
1 5 1
2 5 1
3 5 1
4 5 2
5 7 2
5 7 1
5 7 2
Group Table:
GroupID GroupName
1 Group 1
2 Group 2
GroupToLocation Table:
GroupToLocationID GroupID LocationID
1 1 5
2 2 5
3 2 7
I have gotten to the point where I could sum up the various statuses per location and get this:
LocationID Status1 Status2
5 3 1
7 1 2
Location 5 has 3 Invoices with a status of 1, and 1 invoice with a status of 2 while Location 7 has 1 status 1 and 2 status 2
There are two groups, and Location 5 is in both, while Location 7 is only in the second. I need to be able to set it up where I can append a where statement like this:
select * from vw_GroupCounts
where GroupName = 'Group 2'
or
select Invoice, SUM(*) from vw_GroupCounts
where GroupName = 'Group 2'
And that result in only getting Location 7. Whenever I do this, as I have to use left joins or something along those lines, the counts are duplicating for each group the the Location is affiliated with. I know I could do something along the lines of a subquery and pass in the GroupName into that, but the system I am working with uses a dynamic query builder that appends WHERE statements based on user input.
I don't mind using view, or functions, or any number of functions inside of functions, but I hope there is a way to do what I'm looking for.
Since locations 5 and 7 are in Group 2, if you search for group 2 in the where clause after joining all the tables, then you would get all records in this case, this isn't duplication, just the way the data is. A different join wouldn't change this, only changing the data. Let me know if I am misunderstanding something though.
Here is how you would join them to do that search.
Here it is with your first example of the location and status count.

How to eliminate repeated rows from table with composite primary key ORACLE

I need to find the repeated rows from a table where the first three columns will make up the primary key. Then after finding out which one's are repeated, those repeated rows need to be removed from the query results as this example shows:
Given this table. The first 3 columns act as the primary key.
--------------1 2 3 4 5 6-------------------------------------------------------------------------------------------------------------------------------1 2 3 9 8 9-------------------------------------------------------------------------------------------------------------------------------1 4 3 9 8 9-------------------------------------------------------------------------------------------------------------------------------3 4 2 2 2 1-------------------------------------------------------------------------------------------------------------------------------2 3 4 1 1 3-------------------------------------------------------------------------------------------------------------------------------2 3 4 9 9 0--------
Since 1 2 3 is the composite primary key. The first 2 rows should be considered repeated and therefore eliminated from the results. Just as the two 2 3 4 rows.
The only rows in the result set should be:
1 4 3 9 8 9 and 3 4 2 2 2 1
Could you please help?
Thanks a lot in advance..
Your question doesn't fully make sense. A composite primary key would prevent duplicates in the table. So, these columns are not declared as a comosite primary key if the data contains duplicates.
If you just one one row for each group, you can use row_number() for this, something like this (the column names are obviously invalid):
select t.*
from (select t.*, row_number() over (partition by 1, 2, 3 order by 1) as seqnum
from table t
) t
where seqnum = 1;
If you want to delete extra rows, you can try:
delete from t
where rowid not in (select min(rowid) from table t group by 1, 2, 3);
EDIT:
If you want to remove cases where the rows are repeated, then you want count() instead of row_number():
select t.*
from (select t.*, count() over (partition by 1, 2, 3) as cnt
from table t
) t
where cnt > 1;

ORDER BY Within JOIN Ordering

2I'm trying to perform a kind os sub ordering within an order based on a join.
SELECT
w.*
FROM
[dbo].[Scores] AS w
JOIN #ScoresTable AS s on s.AreaId = w.AreaId
WHERE
[Id] = #Id
ORDER BY
w.Score -- this is where the problem is
ScoresTable is a table variable that has a specific order so my selected data from w is based on its AreaId order.
What I'm trying to do is then sort these results based on the w.Score column but that just seems to "override" the order I get (correctly) from the JOIN clause.
How do I add the Score order whilst still respecting the AreaId order established based on the JOIN?
I've tried using:
ORDER BY
s.AreaId, w.Score
The JOIN results in the correct ordering based on #ScoresTable.AreaId order like:
AreaId
5
3
6
Without the ORDER BY clause I get this (AreaId is ordered as required):
Id Score WheId AreaId ContextId
25 25 2 5 1
26 50 2 5 2
27 2 2 5 3
28 10 2 5 4
29 5 2 5 5
39 1 2 3 11
40 30 2 6 12
All I want to do now is order this on the Score column to get this result set (AreaId is ordered as required and sorted on Score):
Id Score WheId AreaId ContextId
27 2 2 5 3
29 5 2 5 5
28 10 2 5 4
25 25 2 5 1
26 50 2 5 2
39 1 2 3 11
40 30 2 6 12
I would add an AreaOrder column to your #ScoresTable, so it has two columns
AreaOrder, AreaId and then you can
SELECT w.*
FROM
[dbo].[Scores] AS w
JOIN #ScoresTable AS s on s.AreaId = w.AreaId
WHERE [Id] = #Id
ORDER BY
s.AreaOrder, w.Score
There is no such thing as JOIN order. The order you observe when there is no ORDER BY clause is arbitrary. It may be this with these data but once you have one or more (or less) rows or different load on the server or different distribution on the any of the joined tables or the moon gets closer to earth, the query plan may be different and the order of the result set will not be the same.
The point is that you can't and you shouldn't expect a specific ordering if you do not provide an ORDER BY clause.
And from the reuslts you have shown, we may guess that the ordering is based on Id ASC
Now from the limited data you have shown, it seems that you want to group the rows with same AreaId together and order them by Score. The ordering between the various values of AreaId though, seems strange (5 -> 3 -> 6).
If you want that to be affected by the Id column, the following may be what you are after:
ORDER BY
MIN(w.Id) OVER (PARTITION BY w.AreaId),
w.Score ;
(and note that if you replace the MIN(w.id) with MAX(w.Id), you'll get the same results with the specific data. If the rest of your data comply with that, we can't know for sure.)
I see a descending order in AreaId, so you would want to repeat that in your query. The Order By in the current query is always leading over the Order By in any subquery or view.
ORDER BY
s.AreaId desc, w.Score