How to sum/group/sort columns in a view - sql

I have two tables, Author_Dim and Author_Fact as below:
CREATE TABLE Author_Dim
(
TitleAuthor_ID INT IDENTITY(1,1),
Title_ID CHAR(20),
Title VARCHAR(80),
Type_Title CHAR(12),
Author_ID CHAR(20),
Last_Name VARCHAR(40),
First_Name VARCHAR(20),
Contract_Author BIT,
Author_Order INT,
PRIMARY KEY (TitleAuthor_ID),
);
GO
CREATE TABLE Author_Fact
(
Fact_ID INT IDENTITY(1,1),
TitleAuthor_ID INT,
Author_ID CHAR (20),
Price DEC(10,2),
YTD_Sales INT,
Advance DEC(10,2),
Royalty INT,
Royalty_Perc INT,
Total_Sales DEC(10,2),
Total_Advance DEC(10,2),
Total_Royalty DEC(10,2)
PRIMARY KEY(Fact_ID),
FOREIGN KEY (TitleAuthor_ID) REFERENCES Author_Dim(TitleAuthor_ID),
);
go
I wish to create a view that gives the total royalties paid per author and then sorts it with the highest paid author shown first, i.e. it sums the Total_Royalty column, groups it by the Author_ID and then sorts the Total_Royalty in descending order.
I have the below but I'm not sure how to add the sum/group/sort functions to the view:
Create view [Total_Royalty_View] As (
Select Author_Dim.Author_ID, Author_Dim.Last_Name, Author_Dim.First_Name, Author_Fact.Total_Royalty
From Author_Dim
Join Author_Fact
On Author_Fact.TitleAuthor_ID = Author_Dim.TitleAuthor_ID
);
Go

In SQL it is all tables. You select from tables and the result is again a table (consisting of columns and rows). You can store a select statement for re-use and this is called a view. You could just as well write an ad-hoc view (a subquery in a from clause). Their results are again tables.
And tables are considered unordered sets of data.
So, you cannot write a view that produces an ordered set of rows.
Here is the view (unordered):
create view total_royalty_view as
select
a.author_id,
a.last_name,
a.first_name,
coalesce(r.sum_total_royalty, 0) as total_royalty
from author_dim a
left join
(
select titleauthor_id, sum(total_royalty) as sum_total_royalty
from author_fact
group by titleauthor_id
) r on r.titleauthor_id = a.titleauthor_id;
And here is how to select from it:
select *
from total_royalty_view
order by total_royalty desc;

Related

Nested Query with just displaying Row Number

I am trying to display just the rownumber from a select query.
CREATE TABLE UserInfo(
UserID INT,
modName varchar(255),
modCode varchar(8),
credits INT,
ClassPW INT,
CONSTRAINT FK_UserInfo FOREIGN KEY (UserID) REFERENCES LoginTable
);
I managed to do this:
select ROW_NUMBER() OVER(ORDER BY UserID) AS rownum ,modcode from userinfo where userID = 1
But that displays the rownum and modcode with it. I just want to display the rownum and the only way I can think of doing that is a nested query but can't seem to get it right.

Can't figure out Oracle update query involving two different tables

The SQL relation between two table is like below:
CREATE TABLE meve_hall (
hallNo NUMBER,
hallName varchar(20),
seatCapacity NUMBER,
PRIMARY KEY(hallNo)
)
CREATE TABLE meve_student (
stuId NUMBER,
name varchar(20),
dept varchar(20),
hallNo NUMBER,
PRIMARY KEY(stuId),
FOREIGN KEY(hallNo) REFERENCES meve_hall(hallNo)
)
Now the question is:
Change the hallName= 'Ziaur' of those students who is in dept='CSE'
You can write an UPDATE statement WHERE hallNo IN and a subquery to get the hallNo based on dept = 'CSE'.
UPDATE meve_hall SET hallName = 'Ziaur'
WHERE hallNo IN (SELECT hallNo FROM meve_student WHERE dept = 'CSE')
Demo here.

Select from a Temp table is giving slow performance

I need some help with the below query where the last step of
Select * from #PersonDetail order by....
is taking so long to execute - why?
There are millions of records being inserted in this temp table #PersonDetail and insert process takes a few seconds, but the last Select from this same temp table is taking so long.
I created a unique clustered index on the columns used for order by and tried many other options but it doesn't make any difference in the performance.
It is a big stored procedure with many temp table but it is this last select step which is impacting the performance. Here is an example of the last step of the query:
DROP TABLE IF EXISTS #PersonDetail
CREATE TABLE #PersonDetail
(
PersonId INT NOT NULL,
Name NVARCHAR(50) NULL,
Number INT NOT NULL,
Tag NVARCHAR(50) NULL,
UserId INT NOT NULL,
NumberEncrypted VARCHAR(100),
Type NVARCHAR(255),
Status NVARCHAR(50),
CreatedDate DATETIMEOFFSET(7),
AddressDetailId NVARCHAR(50),
Category NVARCHAR(50),
PrimaryId INT,
DailyAmount MONEY,
UNIQUE (PersonId UserId),
UNIQUE CLUSTERED(CreatedDate, UserId)
)
INSERT INTO #PersonDetail (PersonId, Name, Number, Tag, UserId, NumberEncrypted,
Type, Status, CreatedDate, AddressDetailId, Category, PrimaryId, Amount)
SELECT
PersonId, Name, Number, Tag, UserId, NumberEncrypted,
Type, Status, CreatedDate, AddressDetailId, Category, PrimaryId, DailyAmount
FROM
#User u
JOIN
dbo.DailyAmount da (NOLOCK) ON da.UserId = u.UserId
SELECT *
FROM #PersonDetail pd
ORDER BY CreatedDate, UserId
You must specify what database are you using.
In general, you must do theese things:
create some indexes on the join columns (DailyAmount.userId, User.userID); how to create the index must change;
create an index on the order by columns, (CreatedDate+UserID); this must change, in postgresql for example an index with the 2 column is better than 2 indexes;
If your data are not changing frequently, you could try materialized view and create the indexes on the materialized view.

Creating and populating a table in T-SQL

I'm new to T-SQL and trying to learn how to create a script in T-SQL to create and populate a table(StaffData).The StaffData is defined as below:
staffid – integer primary key, identity starting at 1, increments by 1
managerid – int, allows nulls, pointer to another record in managertable
name – string of 50 characters
salary – money
What can I do to generate table and fill it with set of data..?
Here's the correct SQL. I've tested it (just spotted that you want managerId nullable - I've added this):
it uses better conventions for your table and column names (you shouldn't be using 'data' in table names - we know it contains data)
it names your primary key constraints, which is better practice - you can do something similar for the FK constraint if you want, I've just done it inline
it uses 'USE' and 'GO' statements to ensure you're creating things on the right database (critical when you're working on big production systems).
it uses nvarchar columns - you need these to reliably store data from international character sets (e.g the manager has a Russian name)
I'm using nvarchar(max) as you can't be sure that a name will only be 50 characters. Use nvarchar(50) if you must, but database space isn't usually a big deal.
You need to create the Manager table first, as your Staff table depends on it:
USE [yourDatabaseName] -- you don't need the square brackets, but they don't hurt
-- Create ManagerTable
CREATE TABLE Manager
(
id int IDENTITY(1,1),
name nvarchar(max),
CONSTRAINT pk_manager PRIMARY KEY (id)
)
CREATE TABLE Staff
(
id int IDENTITY(1,1),
name nvarchar(max),
salary money,
managerId int FOREIGN KEY REFERENCES Manager(id) NULL,
CONSTRAINT pk_staff PRIMARY KEY (id)
)
--To populate Manager table:
INSERT INTO [Manager]
(
-- id column value is auto-generated
name
)
VALUES
(
'John Doe'
)
--To populate Staff table:
INSERT INTO [Staff]
(
-- id column value is auto-generated
name, salary, managerId
)
VALUES
(
'Jane Doe', 60000, 1
)
GO
To create the two database tables:
-- Create StaffData
CREATE TABLE StaffData
(
staffid int PRIMARY KEY IDENTITY,
managerid int
)
-- Create ManagerTable
CREATE TABLE ManagerTable
(
managerid int,
name varchar(50),
salary money
)
To populate StaffData table:
INSERT INTO [StaffData]
(
--staffid - this column value is auto-generated
[managerid]
)
VALUES
(
-- staffid - int
12345 -- managerid - int
)
To populate ManagerTable table:
INSERT INTO [ManagerTable]
(
[managerid],
[name],
[salary]
)
VALUES
(
12345, -- managerid - int
'Juan Dela Cruz', -- name - varchar
15000 -- salary - money
)
To select the data if i understand you in your word Pointer here is the query using INNER JOIN joining the two tables using their managerid
SELECT *
FROM [StaffData]
INNER JOIN [ManagerTable]
ON [StaffData].managerid = [ManagerTable].managerid

Delete duplicate rows with soundex?

I have two tables, one has foreign keys to the other. I want to delete duplicates from Table 1 at the same time updating the keys on Table 2. I.e count the duplicates on Table 1 keep 1 key from the duplicates and query the rest of the duplicate records on Table 2 replacing them with the key I'm keeping from Table 1. Soundex would be the best option because not all the names are spelled right in Table 1. I have the basic algorithm but not sure how to do it. Help?
So far this is what I have:
declare #Duplicate int
declare #OriginalKey int
create table #tempTable1
(
CourseID int, <--- The Key I want to keep or delete
SchoolID int,
CourseName nvarchar(100),
Category nvarchar(100),
IsReqThisYear bit,
yearrequired int
);
create table #tempTable2
(
CertID int,
UserID int,
CourseID int, <---- Must stay updated with Table 1
SchoolID int,
StartDateOfCourse datetime,
EndDateOfCourse datetime,
Type nvarchar(100),
HrsOfClass float,
Category nvarchar(100),
Cost money,
PassFail varchar(20),
Comments nvarchar(1024),
ExpiryDate datetime,
Instructor nvarchar(200),
Level nchar(10)
)
--Deletes records from Table 1 not used in Table 2--
delete from Table1
where CourseID not in (select CourseID from Table2 where CourseID is not null)
insert into #tempTable1(CourseID, SchoolID, CourseName, Category, IsReqThisYear, yearrequired)
select CourseID, SchoolID, CourseName, Category, IsReqThisYear, yearrequired from Table1
insert into #tempTable2(CertID, UserID, CourseID, SchoolID, StartDateOfCourse, EndDateOfCourse, Type, HrsOfClass,Category, Cost, PassFail, Comments, ExpiryDate, Instructor, Level)
select CertID, UserID, CourseID, SchoolID, StartDateOfCourse, EndDateOfCourse, Type, HrsOfClass,Category, Cost, PassFail, Comments, ExpiryDate, Instructor, Level from Table2
select cour.CourseName, Count(cour.CourseName) cnt from Table1 as cour
join #tempTable1 as temp on cour.CourseID = temp.CourseID
where SOUNDEX(temp.CourseName) = SOUNDEX(cour.CourseName) <---
The last part does not exactly work, gives me an error
Error: Column 'Table1.CourseName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
UPDATE: Some of the names in CourseName have numbers in them too. Like some are in romans and numeral format. Need to find those too but Soundex ignores numbers.