SQL Union with fixed number of rows as result - sql

This is a simple representation of my student table.
Student
Year
Class
1
2010
A
2
2010
A
3
2010
C
4
2010
B
5
2011
B
6
2012
B
I want to compose a random group of 5 students.
In the group there will be 2 students of year 2010 and 3 students of group B. These values are user specified.
A simple union doesn't always work, because of the duplicate values. Sometimes there are 4 students, sometimes there are 5 students. I always want 5 records.
SELECT * FROM (SELECT TOP 2 * FROM [Student] WHERE YEAR = 2010 ORDER BY NEWID()) A
UNION
SELECT * FROM (SELECT TOP 3 * FROM [Student] WHERE Class = 'B' ORDER BY NEWID()) B
Is this possible with a SQL query?

Related

SQL Query -- AVG for Occurrence Across Multiple Columns

I have a table like the following
ID_A
ID_B
Avg_Class_Size
1
2
16
3
4
10
2
3
8
2
4
9
Where ID_A and ID_B represent distinct student ID codes, and AVG_Class_Size represents the average class size of the classes shared between students A and B.
I would like to calculate the average of the "avg_class_size" for each student, regardless of whether they are student "A" or student "B", with results like below:
ID
AVG
1
16
2
11
3
9
4
9.5
Is there a simple way to accomplish this with a SQL query?
Select with UNION ALL all the ids and averages of the students and aggregate:
SELECT ID, AVG(Avg_Class_Size) average
FROM (
SELECT ID_A ID, Avg_Class_Size FROM tablename
UNION ALL
SELECT ID_B ID, Avg_Class_Size FROM tablename
) t
GROUP BY ID
See the demo.
Results:
ID
average
1
16
2
11
3
9
4
9.5

Limiting output with different criterias

I have the following SQL statement:
select
row_number() over(),
car, group, yearout
from (select..... )inner
where year(inner.yearout) between '2010' and '2030'
order by inner.group)temp
the output is like
1 test1 1 2010
2 test2 1 2010
3 test3 1 2012
4 test1 2 2010
5 test1 3 2011
and so on.
There is another table called outerno with is filled like:
no yearo amnt
1 2010 10
2 2010 15
3 2010 5
4 2010 10
5 2010 15
6 2010 8
1 2011 4
2 2011 15
and so on.
There are 6 groups in the table for each year.
Now the problem is that I need to limit the output of the query as stated in the outerno table.
So I need the first 10 row for 2010 for group 1, the first 15 rows of 2010 for group 2 and so on. For each year and group there is a value in the outerno.
I tried to use row_number but I don't know how to limit the output in this way since I would be needing for example rows 1-10, 50-65, 83-88 and so on.
Any idea on how to do this?
Thanks in advance for all your help.
TheVagabond
You'd use ROW_NUMBER() to give you record numbers per group. Then add a WHERE clause to only get row numbers up to the desired number. In ROW_NUMBER's ORDER BY you can spcify which records to prefer.
select row_number() over (), car, group, yearout
from
(
select
row_number() over (partition by inner.group, inner.yearout order by inner.car) as rn,
inner.car, inner.group, inner.yearout
from (select..... ) inner
where inner.yearout between '2010' and '2030'
order by inner.group
) all_records
where all_records.rn <=
(
select amnt
from outerno
where outerno.year = all_records.yearout
and outerno.no = all_records.group
);
BTW: I wouldn't choose group for a column name, as it is a reserved word in SQL.

Cross Join for Missing table (Select all and Select or Insert the Missing Row Only)

I have two table and have to fill in a list of missing values in one of the table based on the other one. First table has student's information and the second table has Grade related info, Grade and Grade description.
Table One
ID Name yearWithUs Grade Course Level
1 Jim 2004 4 4
2 Jim 2004 4 1
2 Jim 2003 3 3
4 Jim 2002 2 3
4 Jim 2002 2 1
3 Jim 2001 1 2
3 Jim 2001 1 1
Table two -- logic is.. A Student in a higher Course Level can change to a lower Course Level at anytime during the semester. And It can only go downward 1 level at a time. Example: Jim in his second grade first was assigned to attend course in level 3. He need to attend course in level 2 first before he can attend course in level 1. Means. Row for course level 2 at jim's first grade is missing.
Table Two
ID Grade Grade_Desc Course Level Course Desc
1 1 First Grade 1 Basic
2 1 First Grade 2 Normal
3 1 First Grade 3 Hard
4 1 First Grade 4 Expert
5 2 Second Grade 1
6 2 Second Grade 2
7 2 Second Grade 3
8 2 Second Grade 4
. . .
. . .
. . .
Logic of Table Two
ID Grade Grade_Desc Course Level Possible Move
1 1 First Grade 1 Null
2 1 First Grade 2 1
3 1 First Grade 3 2
4 1 First Grade 4 3
Ouptput one ... how to use select statement to return Jim's Grade?
ID Name Grade_Desc Grade yerWithUs Course Level
1 Jim Fourth Grade 4 2004 4
2 Jim Fourth Grade 4 2004 3
3 Jim Fourth Grade 4 2004 2
4 Jim Fourth Grade 4 2004 1
5 Jim Third Grade 3 2003 3
6 Jim Second Grade 2 2002 3
7 Jim Second Grade 2 2002 2
8 Jim Second Grade 2 2002 1
9 Jim First Grade 2 2001 2
10 Jim First Grade 2 2001 1
Output Two..How to retrieve only the missing row into a new temp table?
ID Name Grade_Desc Grade yearWithUs Course Level
2 Jim Fourth Grade 4 2004 3
3 Jim Fourth Grade 4 2004 2
7 Jim Second Grade 2 2002 2
I am currently is using a messy Cursor Statement to do it. The structure looks really messy and hard to debug return errors. I did a lot of research, and saw people use Cross Join to fill the missing portion which looks really clean (See example below)... I have tried the script it myself in many different way by using the cross join example below...obviously, I failed. I found a similar question in stackoverflow..but I am not able to understand how does it work and why without looking at the data....I need help to understand how to use cross join to rerun missing row? and I am open to any other possible solution.
"SELECT calendar.Date,
Category.Cat,
Score = ISNULL(Scores.Score, 0)
FROM Calendar
CROSS JOIN Catogory
LEFT JOIN Scores
ON Scores.Cat = Category.Cat
AND Scores.Date = Calendar.Date
WHERE Calendar.DayOfMonth = 1;"
Inserting missing rows with a join
Thank You
This will produce that output:
select distinct name, grade, Grade_Desc
from one
cross join two
If select is all you want then:
Select row_number() over(order by (select 1)) as id, * from
(Select distinct name from t1)t1
cross join t2
Here is fiddle http://sqlfiddle.com/#!6/a8a42/3
Try this out:
Create #Temp
DECLARE #Name VARCHAR(100) = 'Jim'
SELECT ROW_NUMBER() OVER (ORDER BY B.Grade DESC,B.CourseLevel DESC) ID,
A.Name,
B.Grade_Desc,
B.Grade,
A.YearWithUs,
B.[Course Level]
INTO #temp
FROM
(
SELECT DISTINCT Name,YearWithUs,Grade
FROM TableOne
WHERE Name = #Name
) A
INNER JOIN TableTwo B
ON A.Grade = B.Grade
Output One
SELECT *
FROM #temp
Output Two into #OutputTwo(temp table)
SELECT A.* INTO #OutputTwo
FROM #temp A
LEFT JOIN TableOne B
ON A.Grade = B.Grade
AND A.[Course Level] = B.[Course Level]
WHERE A.Grade IS NULL AND A.[Course Level] IS NULL

How to compare two columns in SQL for multiple rows?

I have a data set with four columns (author, document, rating 1, rating 2)
How do I pick authors who have written a document that has been rated higher in rating 1 than rating 2, and has also written another document that has been rated higher in rating 2 than rating 1.
Basically:
AUTHOR DOCUMENT RATING 1 RATING 2
A 1 1 2
B 2 1 2
B 3 3 1
C 4 2 2
C 5 3 4
C 6 1 3
D 7 1 2
D 8 1 2
So my desired query will give me B and C because it has written docs that have had both higher and lower numbers in both ratings.
What I have:
SELECT DISTINCT author
FROM(
(SELECT author
FROM table_name
WHERE rating1 < rating2)
UNION
(SELECT author
FROM table_name
WHERE rating1 > rating2)
)
AS a
What I cant figure out is how to group the authors, test whether rating 1 and rating 2 are both higher and lower, output the name and then move on to the next group of authors. What the above prints is just the set of distinct names with either higher or lower numbers. So this one would print D as well for example.
What is my SQL code missing that would satisfy the criteria mentioned above
Try this,
select *
from myTable as t1
inner join MyTable as t2
on t1.author = t2.author
and t2.rating1 > t2.rating2
where t1.rating1 > t1.rating2

How to write the sql select query for this?

i have mssql tabel like this >
ID Code Rating
1 10 4
2 10 5
3 10 4
4 11 2
5 11 3
The sql query logic i want ...
I want when i search the record using code 10 then the output would be 4 because the 4 rating would be given most of the time for code 10 ....
and another logic if i search for code 11 then the out put will be 3 because 3 will be most recent rate for code 11...
how to write the sql query for im using ASP.NET ( VB)
The first thing you want to do is filter:
SELECT * FROM mytable WHERE Code = 10
You're interested in the 'rating' field:
SELECT Rating FROM mytable WHERE Code = 10
Now you want to count entries for Rating, which can be achieved using a combination of GROUP BY and the COUNT() function:
SELECT COUNT(*), Rating FROM mytable WHERE Code = 10 GROUP BY Rating
Now all that's left is sort by count, descending, and select only the first row:
SELECT TOP 1 Rating FROM mytable WHERE Code = 10 GROUP BY Rating ORDER BY COUNT(*) DESC