Need to create a view for the following scenario - sql

There is an Athelete table consisting of 4 columns.
AtheleteID - Primary Key varchar(20)
name - varchar(20)
country - varchar(20)
rank - integer
And another Participate table where the above atheletes participate on events. consisting of 4 columns.
AtheleteID - Foreign Key varchar(20)
EventID - Composite Primary Key varchar(20)
EventDate - date
position - integer
Question:
I need to create a view named TopAtheletes.
View attributes are AtheleteID,name,rank and the number of times they have achieved position (1,2 or 3)
How do i create the view?
I'm stuck on querying for the number of times the athelete has achieved position 1,2 or 3.

You can first count the no of times they achieved the top positions and then can join that with athlete table -
CREATE VIEW VW_ATHLETE_INFO
AS
SELECT A.AtheleteID
,A.name
,A.rank
,P.cnt
FROM Athelete
JOIN (SELECT AtheleteID, COUNT(CASE WHEN position <= 3 THEN 1 END) CNT
FROM Participate
GROUP BY AtheleteID) P ON A.AtheleteID = P.AtheleteID

Related

Strategy to import a raw dataset into a database with multiple tables

I have a set of AIS data in a single table. The data is based on a ships position, as in latitude and longitude together with a lot of static information such as an identifier, length, width, name and such But to increase efficiency and decrease redundancy I need to split this table into multiple (5) tables (in form of a star schema).
My question is what is the best strategy to go on about this?
My ideas are:
Remove the FK constraints and insert the distinct information into the dimension tables and then later look at how to populate the fact table to connect the dimension tables.
Write a giant SQL query
Write a script / program that might be able to handle this
Example of the data with limited columns:
The schema of the database shows the star schema on the left and the raw data on the right.
Forgive me if I am oversimplifying your use case, but why don't you just 1) create the dimension tables using distinct queries(generating ids in case there isn't any), 2) create the fact table with the proper constraints and 3) populate the fact table based on the original and the dimension tables with the new ids, for instance:
Data Sample:
CREATE TEMPORARY TABLE ais_data (
ship_name TEXT,
lat NUMERIC,
lon NUMERIC,
tmstp TIMESTAMP
);
INSERT INTO ais_data VALUES
('foo',1,2,'2021-02-19 12:10:25'),
('foo',1,3,'2021-02-19 12:20:25'),
('foo',1,4,'2021-02-19 12:30:25'),
('bar',1,2,'2021-02-19 12:10:25'),
('bar',1,4,'2021-02-19 12:30:25');
Creating dimensions
CREATE TEMPORARY TABLE ship_dim (
ship_id SERIAL PRIMARY KEY,
ship_name TEXT
);
INSERT INTO ship_dim (ship_name)
SELECT DISTINCT ship_name FROM ais_data;
CREATE TEMPORARY TABLE position_dim (
position_id SERIAL PRIMARY KEY,
lon NUMERIC, lat NUMERIC,
geom GEOMETRY(POINT,4326),
tmstp TIMESTAMP
);
INSERT INTO position_dim (lon,lat,tmstp,geom)
SELECT DISTINCT lon,lat,tmstp,ST_MakePoint(lon,lat)
FROM ais_data;
Creating fact table ...
CREATE TEMPORARY TABLE data_point_fact (
ship_id INT REFERENCES ship_dim(ship_id),
position_id INT REFERENCES position_dim(position_id)
);
... and populating it
INSERT INTO data_point_fact
SELECT s.ship_id,p.position_id FROM ais_data a
JOIN ship_dim s ON s.ship_name = a.ship_name
JOIN position_dim p ON p.lon = a.lon AND p.lat = a.lat AND p.tmstp = a.tmstp;
SELECT * FROM data_point_fact;
ship_id | position_id
---------+-------------
1 | 3
1 | 1
2 | 3
2 | 2
2 | 1
See this db<>fiddle (without geometry)

How to update a column in a table A using the value from another table B wherein the relationship between tables A & B is 1:N by using max() function

I have two tables namely loan_details and loan_his_mapping with 1:N relationship. I need to set the hhf_request_id of loan_details table by the value which is present in the loan_his_mapping table for each loan.
Since the relationship is 1:N , I want to consider the record for each loan from loan_his_mapping table with two conditions mentioned below. The table definitions are as follows:
CREATE TABLE public.loan_details
(
loan_number bigint NOT NULL,
hhf_lob integer,
hhf_request_id integer,
status character varying(100),
CONSTRAINT loan_details_pkey PRIMARY KEY (loan_number)
);
CREATE TABLE public.loan_his_mapping
(
loan_number bigint NOT NULL,
spoc_id integer NOT NULL,
assigned_datetime timestamp without time zone,
loan_spoc_map_id bigint NOT NULL,
line_of_business_id integer,
request_id bigint,
CONSTRAINT loan_spoc_his_map_id PRIMARY KEY (loan_spoc_map_id),
CONSTRAINT fk_loan_spoc_loan_number_his FOREIGN KEY (loan_number)
REFERENCES public.loan_details (loan_number) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION );
The joining conditions while updating are:
The Records of loan_details with hhf_lob = 4 and status='Release'
I should consider that record for updating value among 'N' number of records from loan_his_mapping table with value max(loan_spoc_map_id) for each loan.
The query I have right now
update lsa_loan_details ldet
set hhf_request_id = history.request_id
from loan_his_mapping history
where ldet.loan_number = history.loan_number and ldet.status='Release' and ldet.hhf_lob=4 and
history.line_of_business_id=4 ;
I want to know how to use that record for each loan from loan_his_mapping with max(loan_spoc_map_id) to update column of loan_details table. Please Assist!
You need a sub-query to fetch the row corresponding to the highest loan_spoc_map_id
Something along the lines:
update loan_details ldet
set hhf_request_id = history.request_id
from (
select distinct on (loan_spoc_map_id) loan_number, request_id
from loan_his_mapping lhm
where lhm.line_of_business_id = 4
order by loan_spoc_map_id desc
) as history
where ldet.loan_number = history.loan_number
and ldet.status = 'Release'
and ldet.hhf_lob = 4;

How do you design a table with 3 compound primary keys

I have a table with columns Form, Appraiser, date and Level
A form can never have same appraisers, and a form can never have same Levels.
I tried to make primary key(Form,appraiser) and primary key(Form,level) but it says that form has multiple primary keys
If i put primary key(form,appraiser,level) people can just insert the same form and appraiser twice but just with a different level and that violates my rules.
|Form|Appraiser|Level|
1 A 1
1 B 2
1 C 3
2 A 1
2 B 2
2 C 3
I believe you could use :-
CREATE TABLE IF NOT EXISTS mytable (form INTEGER, appraiser TEXT, level INTEGER, UNIQUE(form,appraiser), UNIQUE(form,level));
e.g. Using the following
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (form INTEGER, appraiser TEXT, level INTEGER, UNIQUE(form,appraiser), UNIQUE(form,level));
INSERT INTO mytable VALUES
(1,'A',1),(1,'B',2),(1,'C',3),
(2,'A',1),(2,'B',2),(2,'C',3)
;
INSERT OR IGNORE INTO mytable VALUES (1,'A',4);
INSERT OR IGNORE INTO mytable values (1,'Z',1);
The results are :-
INSERT INTO mytable VALUES
(1,'A',1),(1,'B',2),(1,'C',3),
(2,'A',1),(2,'B',2),(2,'C',3)
> Affected rows: 6
> Time: 0.083s
all added
but
INSERT OR IGNORE INTO mytable VALUES (1,'A',4)
> Affected rows: 0
> Time: 0s
not added as A has already apprasied form 1.
and also
INSERT OR IGNORE INTO mytable values (1,'Z',1)
> Affected rows: 0
> Time: 0s
not added as for 1 has already been appraised at level 1
We can try using two junction tables here:
CREATE TABLE form_appraiser (
form_id INTEGER NOT NULL,
appraiser_id INTEGER NOT NULL,
PRIMARY KEY (form_id, appraiser_id)
);
CREATE TABLE form_level (
form_id INTEGER NOT NULL,
level_id INTEGER NOT NULL,
PRIMARY KEY (form_id, level_id)
);
Each of these two tables would ensure that a given form can only be associated with a single appraiser or level.
Then, maintain a third table forms containing one record for each unique form. If you have the additional requirement that a given form can only have one appraiser or level, then add a unique constraint on the form, on one/both of the junction tables.
You can try add the unique constraint as a column identifier.
like
appraiser VARCHAR(50) UNIQUE,
form VARCHAR(50) UNIQUE,
level VARCHAR(50) UNIQUE,
In this case non of the values repeats. If you want a combination of values not to repeat you can use
UNIQUE(form, level)
This means you cannot have a form of the same level repeating.

Compare values from 2 tables and produce a new table with the differences

I'm trying to find a way in SQL Server (script) to:
Given 2 tables, with identical column structure
Filled with rows sharing an identical key
But with different values in one of the columns (INTEGER)
Find rows with the matching key in both tables and compare them to produce a new row. in a different table, with the exact same matching values in the rest of the columns and the difference in value between the only non-matching column.
Ex. It's the same db in 4 versions, every new iteration accumulating the values of the previous version, what I'm trying to achieve is a new db with the difference (like in db1 the amount of apples sold is 5, and in db2 the amount of apples sold is 20, I need a new row in a new table with a value of 15).
CREATE TABLE foo (
theKey int NOT NULL IDENTITY(1,1) PRIMARY KEY,
someInt int
)
CREATE TABLE bar (
theKey int NOT NULL IDENTITY(1,1) PRIMARY KEY,
otherInt int
)
CREATE TABLE output (
theKey int NOT NULL PRIMARY KEY,
someInt int,
otherInt int,
valueDifference int
)
INSERT INTO output ( theKey, someInt, otherInt, valueDifference )
SELECT
foo.theKey,
foo.someInt,
bar.otherInt,
foo.someInt - bar.otherInt AS valueDifference
FROM
foo
INNER JOIN bar ON foo.theKey = bar.theKey

SQL database query display extra dates

I am making a database with postgresql 9.1
Given tables:
CREATE TABLE rooms(
room_number int,
property_id int,
type character varying,
PRIMARY KEY (room_number, property_id)
);
Insert into rooms values (1,1,double),(2,1,double),(3,1,triple)
CREATE TABLE reservations(
reservation_ID int,
property_id int,
arrival date,
departure date,
room_num int,
PRIMARY KEY(reservation_ID,property_id)
FOREIGN KEY (room_number, property_id)
);
INSERT INTO orders VALUES (1,1,2013-9-27,2013-9-30,1),
(2,1,2013-9-27,2013-9-28,2),
(3,1,2013-9-29,2013-9-30,3);
I want to give 2 dates and check availability in between. So at the 1st column should apear:
all the dates between the given and
additional one column for every type of the room displaying the availability.
So my result, given 2013-9-27 & 2013-9-30 as input, must be sth like this:
I think the best solution would be use both generate_series() and crosstab() to create a dynamic table. Moreover you can use a left join from a CTE to your data tables so you get better information. Something like:
WITH daterange as (
SELECT s::date as day FROM generate_series(?, ?, '1 day')
)
SELECT dr.day, sum(case when r.type = 'double' then r.qty else 0) as room_double,
sum(case when r.type = 'triple' then r.qty else 0) as room_triple....
);
But note that crosstab would make the second query a little easier.