LEFT JOIN with EXTRA INFORMATION - sql

I have 2 tables
table1: households
Serial_no
Address
sn1
New York
sn2
Maryland
sn3
France
table2: citizens
Serial_id
Fullname
Role
household_id
1
John
Head
sn1
2
Jane
Spouse
sn1
3
Johny
Son
sn1
4
Mike
Head
sn2
I want the output to be like this:
Serial_no
Address
Total_count
Head
sn1
New York
3
John
sn2
Maryland
1
Mike
sn3
France
0
null
I'm stuck here. please help. Thanks in advance!

You can use conditional aggregation with group by like below:
Schema and insert statements:
create table households(Serial_no varchar(10), Address varchar(50));
insert into households values('sn1', 'New York');
insert into households values('sn2', 'Maryland');
insert into households values('sn3', 'France');
create table citizens(Serial_id int, Fullname varchar(50), Role varchar(10), household_id varchar(10));
insert into citizens values(1,'John', 'Head', 'sn1');
insert into citizens values(2,'Jane', 'Spouse', 'sn1');
insert into citizens values(3,'Johny', 'Son', 'sn1');
insert into citizens values(4,'Mike', 'Head', 'sn2');
Query:
select Serial_no,Address,count(c.household_id) Total_count,
max(case when Role='Head' then Fullname end) Head
from households h
left join citizens c
on h.Serial_no=c.household_id
group by Serial_no,Address
Output:
Serial_no
Address
Total_count
Head
sn1
New York
3
John
sn2
Maryland
1
Mike
sn3
France
0
null
db<>fiddle here

Related

Turning rows to columns in postgres

I have one table with rental contracts. (Postgres v10.18)
Like this:
Table Rental
Id Start Main_tenant_id Obect_id
101011 1.1.2021 1000 200
100222 1.1.2021 2050 210
If the Object has more than one Tenant the other ones a saved in a separate Table like this:
Table Rental_extra
Id rental_id xtra_tenant
20001 100222 3000
20002 100222 2700
20003 100222 2800
And i have a Person table like this:
Table Person
Id first_name last_name
1000 Peter Mcdonald
2050 Dan Hunt
3000 Steve Cole
2700 Ian Wright
2800 William Pears
Now i need to get this output:
Goal
Id tenant 1 tenant 2 tenant 3 tenant 4
101011 Peter Mcdonald null null null
100222 Dan Hunt Steve Cole Ian Wright William Pears
What's the best way? I tried with some crosstab example but couldn't make it work.
SELECT *
FROM crosstab(
$$
SELECT t.id, tenant_nr, concat_ws(' ', p.first_name, p.last_name)
FROM (
SELECT id, 0 AS tenant_nr, main_tenant_id AS tenant_id
FROM rental
UNION ALL
SELECT rental_id, row_number() OVER (PARTITION BY rental_id ORDER BY id), xtra_tenant
FROM extra_tenant
) t
JOIN person p ON p.id = t.tenant_id
ORDER BY 1 DESC, t.tenant_nr
$$
) AS goal(id int, tenant_1 text, tenant_2 text, tenant_3 text, tenant_4 text);
db<>fiddle here
Detailed explanation here:
PostgreSQL Crosstab Query
Postgres - Transpose Rows to Columns

SQL Server convert row values to columns

I have an SQL table like this
Name1 Name2 Department1 Department2 Location1 Location2
----------------------------------------------------------------------
Jhon Alex IT Marketing London Seattle
Mark Dan Sales R&D Paris Tokyo
How can I query these results in this format:
Name Department Location
---------------------------------------
Jhon IT London
Alex Marketing Seattle
Mark Sales Paris
Dan R&D Tokyo
Use cross apply
DEMO
select name,department,location
from t
cross apply
(
values(name1,department1,location1),(name2,department2,location2)
)cc (name, department,location)
OUTPUT:
name department location
Jhon IT London
Alex Marketing Seattle
Mark Sales Paris
Dan R&D T Tokyo
You could try to use SQL Server's UNPIVOT operator, but honestly a plain union query might even perform better:
SELECT Name1 AS Name, Department1 AS Department, Location1 AS Location FROM yourTable
UNION ALL
SELECT Name2, Department2, Location2 FROM yourTable;
Regarding your expected ordering, there is no sort of id column in your original table which maintains to which name pair each record belongs. So, what I have written above might be the best we can do here.
Try This:
DECLARE #TestDemo AS TABLE(Name1 VARCHAR(10),Name2 VARCHAR(10),Department1 VARCHAR(10),Department2 VARCHAR(10),Location1 VARCHAR(10),Location2 VARCHAR(10))
INSERT INTO #TestDemo VALUES('Jhon','Alex','IT','Marketing','London','Seattle')
INSERT INTO #TestDemo VALUES('Mark','Dan','Sales','R&D','Paris','Tokyo')
SELECT Name1 'Name',Department1 'Department',Location1 'Location' FROM #TestDemo
UNION ALL
SELECT Name2 'Name',Department2 'Department',Location2 'Location' FROM #TestDemo

Adding a new column to an existing table in an access ODBC database from R

I am trying to add a new column to an existing table in access using R.
I cannot figure out the way to do it. This is what I tried:
install.packages("RODBC")
require(RODBC)
channel <- odbcConnect("Access01", believeNRows=FALSE)
df <- sqlFetch(channel, "Customers")
df
ID Last_Name First_Name Email_Address Business_Phone Home_Phone Mobile_Phone Fax_Number Address
1 1 Sam Marty mlast#123.com 7771234567 8882626262 9998283838 5551717171 123 Main St.
2 2 Sam Sally sfirst#123.com 5557778888 5558889999 5559991111 5552223333 234 Second Ave
City State_Province ZIP_Postal_Code Country_Region Sex Date_of_birth
1 Anywhere ST 55555 USA M 1960-02-03
2 guirao ST 22222 USA f 1975-12-12
df <- cbind(df, test=c("A", "B")
df
ID Last_Name First_Name Email_Address Business_Phone Home_Phone Mobile_Phone Fax_Number Address
1 1 Sam Marty mlast#123.com 7771234567 8882626262 9998283838 5551717171 123 Main St.
2 2 Sam Sally sfirst#123.com 5557778888 5558889999 5559991111 5552223333 234 Second Ave
City State_Province ZIP_Postal_Code Country_Region Sex Date_of_birth test
1 Anywhere ST 55555 USA M 1960-02-03 A
2 guirao ST 22222 USA f 1975-12-12 B
sqlUpdate(channel, df, tablename = "Customers", index="ID")
**Error in sqlUpdate(channel, df, tablename = "Customers", index = "ID") :
data frame column(s) test not in database table**
I also tried to use the sqlSave command but as far as I know it just let you append new rows.
Is it a database structure problem or am I doing something wrong with the R commands?
Thanks in advance.
It looks like sqlUpdate() does not alter the structure of the table automatically (not that I would expect it to). So, you'll probably have to so something like
sqlQuery(channel, 'ALTER TABLE Customers ADD COLUMN test TEXT(1)')
before you try to apply the update.

getting wrong result

Hospital_Visit
hid pid HospitalName DoctorId
41 1 abc 1
42 2 xyx 2
Patient_Master
pid PatientName
1 jill
2 rosy
Doctor_Master
DoctorID DoctorName
1 John
2 Jack
Hospital_Study
sid hid exam status
1 41 jjj sfvn
2 41 fks jdjd
select Hospital_Visit.Pid,PatientName,DoctorName from Patient_Master
inner join Hospital_Visit on Hospital_Visit.pid=Patient_Master.pid
inner join Doctor_Master on Doctor_Master.DoctorID= Hospital_Visit.DoctorID
inner join Hospital_Study on Hospital_Study.hid=Hospital_Visit.hid
Pid PatientName DoctorName exam status
1 Jill John jjj sfvn
2 rosy John fks jdjd
**
//Correct output i want
Pid PatientName DoctorName exam status
1 Jill John jjj sfvn
2 rosy Jack fks jdjd
**
i am getting wrong result repeting doctor
name in result because of inner join hid on Hospital_Visit and Hospital_Study
How can i takle this problem
(DTU Edit - Current sample data in usable form):
create table Hospital_Visit(hid int,pid int,HospitalName char(3), DoctorId int)
insert into Hospital_Visit(hid, pid, HospitalName, DoctorId) values
(41, 1, 'abc', 1),
(42, 2, 'xyx', 2)
create table Patient_Master(pid int, PatientName char(4))
insert into Patient_Master(pid, PatientName) values
(1, 'jill'),
(2, 'rosy')
create table Doctor_Master(DoctorID int, DoctorName char(4))
insert into Doctor_Master(DoctorID, DoctorName) values
(1, 'John'),
(2, 'Jack')
create table Hospital_Study(sid int, hid int, exam char(3), status char(4))
insert into Hospital_Study(sid, hid, exam, status) values
(1, 41, 'jjj' ,'sfvn'),
(2, 41, 'fks' ,'jdjd')
With the sample data given right now (revision 4), it's impossible to get the output you want.
Right now, your query returns this:
Pid PatientName DoctorName
1 jill John
1 jill John
What you want is this:
//Correct output i want
Pid PatientName DoctorName exam status
1 Jill John jjj sfvn
2 rosy Jack fks jdjd
...but the data in the Hospital_Study table doesn't match this, because both lines have hid = 41:
Hospital_Study
sid hid exam status
1 41 jjj sfvn
2 41 fks jdjd
So they both reference the first row from the Hospital_Visit table, which belongs to the patient named "Jill".
--> with this data, it's impossible to select the patient named "rosy", because there is no row in the Hospital_Study table that refers to rosy's visit (hid = 42).
To get the desired output, the data in the Hospital_Study would need to look like this:
Hospital_Study
sid hid exam status
1 41 jjj sfvn
2 42 fks jdjd
/\
||
this is different
With this data, and the exact query from your question, you get this result:
Pid PatientName DoctorName
1 jill John
2 rosy Jack
I have a doubt on your join
inner join Hospital_Study on Hospital_Study.hid=Hospital_Visit.hid
Hospital_Study.hid is Foreign key that's right but Hospital_Visit.hid is a primary key or is it a foreign key.
If Hospital_Visit.hid is a foreign key of then you have to add one more inner join on your Hospital's Master table (Hospital_Master).

How do you write an insertion statement (SQL) for IS-A relationships?

I have a IS-A relationship between actor and person.
I understand how to write an insertion statement for PERSON. But how would I connect that
to ACTOR?
EDIT: To clarify, is there a way to do this besides setting the relationship manually?
CREATE TABLE person
(
person_id INT,
person_name VARCHAR(20),
birth_year CHAR(4),
gender CHAR(1),
PRIMARY KEY(person_id)
);
CREATE TABLE actor
(
actor_id INT NOT NULL REFERENCES person(person_id),
PRIMARY KEY(actor_id)
);
That depends how you are determining who is an actor. If you already know this at the time of insertion into the person table, then you can just use another INSERT statement to insert the row into the actor table as well.
If you already have the person table defined and want to identify particular people and tag them as actors (i.e. by name), you could do something like:
INSERT INTO actor (actor_id)
SELECT person_id
FROM person
WHERE person_name = 'Will Smith';
http://sqlfiddle.com/#!2/ce898/9
Either way, as long as the actor_id in actor matches a valid person_id in person, the INSERT will be valid. If no corresponding person_id exists, the INSERT will fail.
If in case you are using Postgres, you can do inheritance, just like in OOP:
CREATE TABLE person
(
person_id serial primary key,
person_name VARCHAR(20),
birth_year CHAR(4),
gender CHAR(1)
);
create table actor
(
role text
) inherits(person);
Test:
insert into person(person_name,birth_year,gender)
values('john lennon','1940','M');
insert into actor(person_name,birth_year,gender,role)
values('johnny depp','19xx','M','hacker');
insert into actor(person_name,birth_year,gender,role)
values('johnny walker','19xx','M','walker');
select * from person order by person_name;
select * from actor order by person_name;
Output:
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER
1 john lennon 1940 M
2 johnny depp 19xx M
3 johnny walker 19xx M
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER ROLE
2 johnny depp 19xx M hacker
3 johnny walker 19xx M walker
----------------------------------------------------------------
update actor set
role = 'pirates', birth_year = 1963
where person_name = 'johnny depp';
select * from person;
select * from actor;
Output:
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER
1 john lennon 1940 M
2 johnny depp 1963 M
3 johnny walker 19xx M
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER ROLE
2 johnny depp 1963 M pirates
3 johnny walker 19xx M walker
----------------------------------------------------------------
delete from actor where person_name = 'johnny depp';
select * from person;
select * from actor;
Output:
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER
1 john lennon 1940 M
3 johnny walker 19xx M
PERSON_ID PERSON_NAME BIRTH_YEAR GENDER ROLE
3 johnny walker 19xx M walker
Live test: http://www.sqlfiddle.com/#!1/463f4/1
Please try this
INSERT INTO ACTOR (ACTOR_ID) SELECT P.PERSON_ID FROM PERSON P LEFT JOIN ACTOR A ON P.PERSON_ID=A.ACTOR_ID
Thanks
Rajath