Select from multiple tables with group by clause - sql

I have these table in my database :
Ticket
-------------------------------
|ID int PK |
|Paid varchar(50) |
-------------------------------
TicketRow
----------------------------------
|ID int PK |
|TicketID_FK int |
|SHtimeID_FK int |
----------------------------------
I want to fetch the duplicated rows, that have same SHTiemID_FK and have Paid='ok' state in Ticket table, from TicketRow table.
I try this :
select SHtimeID_FK,count(*) as cnt from dbo.TicketRow
group by SHtimeID_FK
having count(*)>1
But i don't know how should i add Ticket table in my result set.
UPDATE :
I also need Ticket.ID in my resultset

If I understand your scenario correctly you can simply join these two tables by a inner join as I suppose TicketRow.TicketID_FK is a foreign key to Ticket table.
select SHtimeID_FK,count(*) as cnt
from dbo.TicketRow as tr inner join dbo.Ticket as t on tr.TicketID_FK=t.ID
where t.Paid='ok'
group by SHtimeID_FK
having count(*)>1

Related

SQL to concatenate two columns and join two tables

Table person:
| id | f_name | l_name |
Table sales:
| id | amount | date | itemname |
I have a problem joining the two tables which concat f_name and last_name as fullname column, and joining with table sales. Here id is same on both tables.
Output:
| itemname| date |fullname |
What I have tried:
select *
from
(select
concat(f_name, l_name) as fullname
from
tblperson) p
left join
select itemname, date
from table sales s on s.id = p.id
It should actually be
SELECT table_sales.*, concat(table_person.f_name, table_person.l_name) as fullname
FROM table_person
LEFT JOIN table_sales
ON table_person.id = table_sales.id
have not tested this but that is the syntax
you're missing a field like person_id in your sales table (which references the id field in the person table). You can then use a join to properly join the data together.
You are so close. Try this
select p.*,concat(f_name,l_name)as fullname, s.itemname,s.date, s.amount
from person p left join
sales s on s.id=p.id
Here ia good read on sql join.
https://www.w3schools.com/sql/sql_join.asp

SQL -- SELECT 3 TABLES WITH 2 IDs

I'm trying to join 3 tables where the two IDs from two tables are related but the third table is not related but the values are. It's very convoluted. I tried running a subquery without luck.
Here's the first table:
+---------------------------------+
| ListID | ListValue | ListLabel |
+--------------------------------+
| 1 | 1 | Male |
+--------------------------------+
Second table:
+--------------------+
| ListID | ListName |
+-------------------+
| 1 | Gender |
+-------------------+
Third table:
+---------------------------------+
| ClientID | Name | Gender |
+--------------------------------+
| 23422 | John West | 1 |
+--------------------------------+
So basically I'm looking for the Gender column from the third table to reference the first table where the ListValue column equals the Gender column. Yes, the Gender column value is stored as INT.
+---------------------------------+
| ClientID | Name | Gender |
+--------------------------------+
| 23422 | John West | Male |
+--------------------------------+
From a complete guess, the problem is your design, fix that, fix the problem. You should have 2 tables here, not 3. A Client table and a gender table, and then you can do a trivial JOIN:
CREATE TABLE dbo.Client (ClientID int NOT NULL,
[Name] nvarchar(50) NOT NULL,
Gender tinyint NULL); --As Gender is Sensitive data, and probably not mandatory as some don't wish to share
ALTER TABLE dbo.Client ADD CONSTRAINT PK_Client PRIMARY KEY CLUSTERED (ClientID);
GO
CREATE TABLE dbo.Gender (GenderID tinyint IDENTITY(1,1) NOT NULL,
GenderDescription varchar(15) NOT NULL);
ALTER TABLE dbo.Gender ADD CONSTRAINT PK_Gender PRIMARY KEY CLUSTERED (GenderID);
GO
ALTER TABLE dbo.Client ADD CONSTRAINT FK_ClientGender FOREIGN KEY (Gender) REFERENCES dbo.Gender (GenderID);
GO
--Assume existance of data
SELECT C.ClientID,
C.[Name],
G.GenderDescription AS Gender
FROM dbo.Client C
LEFT JOIN dbo.Gender G On C.Gender = G.GenderID; --LEFT JOIN as it's NULLable
GO
If you must stick with the design you have, you'll probably want to write it as subqueries; and it'll get messy pretty fast:
SELECT T3.ClientID,
T3.[Name],
(SELECT T1.ListLabel
FROM dbo.Table2 T2
JOIN dbo.Table1 T1 ON T2.ListID = T1.ListID
WHERE T2.ListName = N'Gender'
AND T1.ListValue = T3.Gender) AS Gender,
(SELECT T1.ListLabel
FROM dbo.Table2 T2
JOIN dbo.Table1 T1 ON T2.ListID = T1.ListID
WHERE T2.ListName = N'PrimaryLanguage'
AND T1.ListValue = T3.PrimaryLanguage) AS PrimaryLanguage
FROM dbo.Table3 T3;
You can put these (sub)queries in the FROM is you prefer using APPLY. I've used an OUTER rather than CROSS APPLY, as I assume that the value could be NULL and thus acts like a LEFT JOIN, rather than an INNER JOIN:
SELECT T3.ClientID,
T3.[Name],
G.Gender,
PL.PrimaryLanguage
FROM dbo.Table3 T3
OUTER APPLY (SELECT T1.ListLabel AS Gender
FROM dbo.Table2 T2
JOIN dbo.Table1 T1 ON T2.ListID = T1.ListID
WHERE T2.ListName = N'Gender'
AND T1.ListValue = T3.Gender) G
OUTER APPLY (SELECT T1.ListLabel AS PrimaryLanguage
FROM dbo.Table2 T2
JOIN dbo.Table1 T1 ON T2.ListID = T1.ListID
WHERE T2.ListName = N'PrimaryLanguage'
AND T1.ListValue = T3.Gender) PL;
To make it shorter, you could turn the "look up" part of the above into an inline table-value function, but I feel that entertaining that is validating the design, and I specifically don't want to do that.
This'll be a real pain to keep rewriting, but forced by the design choice. Though you could do this with Dynamic SQL, I doubt you'll be able to understand it or maintain it (as if you could understand dynamic SQL you'd have likely at least got the solution I give above), and I doubt you want to write all of your queries as a dynamic statement.
Fix the design, fix the problem (as I mentioned at the start).
This is a very bad data model. Change it if you can.
If there is a column gender in the client table, why muddle through with some generic list? Just add a table gender and link to its rows with client.gender_id:
table gender (gender_id, description)
table client (client_id, name, gender_id)
If you really must make this generic and are ready to live with the consequences (slower access, no guaranteed consistency, ...), then remove the gender column and add a table client_attribut instead, consisting of client_id, list_id and list_value.
Anyway, with your current design the query would be
select c.clientid, c.name, la.listlabel
from client c
join list_attribute la
on la.listvalue = c.gender
and la.listid = (select listid from list where listname = 'Gender')
order by c.clientid;
A simple join is of course possible, it's just unecessarily convoluted!
select t3.ClientId, t3.Name, t1.ListLabel as Gender
from t3 join t2 on t2.ListName='Gender'
join t1 on t1.ListId=t2.ListId and t2.ListValue=t3.Gender

Postgres join and count multiple relational tables

I want to join the 2 tables to the first table and group by a vendor name. I have three tables listed below.
Vendors Table
| id | name
|:-----------|------------:|
| test-id | Vendor Name |
VendorOrders Table
| id | VendorId | Details | isActive(Boolean)| price |
|:-----------|------------:|:------------:| -----------------| --------
| random-id | test-id | Sample test | TRUE | 5000
OrdersIssues Table
| id | VendorOrderId| Details. |
|:-----------|--------------:-----------:|
| order-id | random-id | Sample test|
The expected output is to count how many orders belong to a vendor and how many issues belongs to a vendor order.
I have the below code but it's not giving the right output.
SELECT "vendors"."name" as "vendorName",
COUNT("vendorOrders".id) as allOrders,
COUNT("orderIssues".id) as allIssues
FROM "vendors"
LEFT OUTER JOIN "vendorOrders" ON "vendors".id = "vendorOrders"."vendorId"
LEFT OUTER JOIN "orderIssues" ON "orderIssues"."vendorOrderId" = "vendorOrders"."id"
GROUP BY "vendors".id;```
You need the keyword DISTINCT, at least for allOrders:
SELECT v.name vendorName,
COUNT(DISTINCT vo.id) allOrders,
COUNT(DISTINCT oi.id) allIssues
FROM vendors v
LEFT OUTER JOIN vendorOrders vo ON v.id = vo.vendorId
LEFT OUTER JOIN orderIssues oi ON oi.vendorOrderId = vo.id
GROUP BY v.id, v.name;
Consider using aliases instead of full table names to make the code shorter and more readable.
You are joining along two related dimensions. The overall number of rows is the number of issues. But to get the number of orders, you need a distinct count:
SELECT v.*, count(distinct vo.id) as num_orders,
COUNT(oi.vendororderid) as num_issues
FROM vendors v LEFT JOIN
vendorOrders vo
ON v.id = vo.vendorId LEFT JOIN
orderIssues oi
ON oi.vendorOrderId = vo.id
GROUP BY v.id;
Notes:
Table aliases make the query easier to write and to read.
Quoting column and table names makes the query harder to write and read. Don't quote identifiers (you may need to recreate the tables).
Postgres support SELECT v.* . . . GROUP BY v.id assuming that the id is the primary key (actually, it only needs to be unique). This seems like a reasonable assumption.

Replacing select values with values from other tables

I am trying to query upon a table, where I want to replace it's foreign key with a value the related table has a fk constraint to. I don't know how to explain it better in words - I have made a minimal example to demonstrate my difficulty.
create table customers (
cpr VARCHAR(10) PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
balance INT DEFAULT 0,
customerCpr VARCHAR(10) references customers (cpr) NOT NULL,
);
CREATE TABLE transactions(
id SERIAL PRIMARY KEY,
retriever INT references accounts (id) NOT NULL,
giver INT references accounts (id) NOT NULL,
timestamp timestamp default current_timestamp,
amount INT NOT NULL
);
So I want to query something like
SELECT retrieverCustomer.name, giverCustomer.name, tran.timestamp tran.amount
FROM transactions tran
WHERE tran.retriever = 20 OR tran.giver = 20...
I want it to return this format:
id | retName | gName | timestamp | amount
----+-----------+-------+----------------------------+--------
1 | Elisabeth | Jonas | 2020-05-09 11:07:50.614155 | 1500
2 | Veronica | Peter | 2020-05-09 11:07:50.614155 | 2200
3 |Kristoffer | Jens | 2020-05-09 11:07:50.614155 | 1700
I am not sure how to achieve this, I have tried with some joining and some conditionals but I fail to see the problem through. If someone know how to achieve this or can explain why it is not ideal to do so it would really help me out.
You want to join the acounts and customers table twices, one time as the giver, one time as the retriever:
SELECT cr.name as retriever_customer, cg.name as giver_customer, t.timestamp, t.amount
FROM transactions t
JOIN accounts ar on ar.id = t.retriever
JOIN accounts ag on ag.id = t.giver
JOIN customers cr on cr.cpr = ar.customercpr
JOIN customers cg on cg.cpr = ag.customercpr
WHERE t.retriever = 20 OR t.giver = 20
ORDER BY t.timestamp;
This is a place where a CTE can prove clearer:
with ac as ( -- accounts with the customer name added on
select a.*, c.name
from accounts a join
customers c
on a.customercpr = c.cpr
)
select t.id, acg.name as giver_name, acr.name as retriever_name, t.timestamp, t.amount
from transactions t join
ac acg
on acg.id = t.giver join
ac acr
on acr.id = t.retriever
where 20 in (t.giver, t.retriever);

Join 3 Tables DB

I have 3 tables: CUSTOMERS, REGISTRATION and TUITION table.
The Registration table has foreign key:
ID_CLIENTES (FK)
ID_AULAS (FK)
And primary key:
ID_INSCRICAO
The objective is to create a select, but which has all the tables according to the inscriptions ie (table.attribute):
INSCRICAO.ID_INSCRICAO | INSCRICAO.DATA | CLIENTES.CNOME | AULAS.ANOME | AULAS.DATA | AULAS.VAGAS |
Have tried using the model:
SELECT INSCRICAO.ID_INSCRICAO,
INSCRICAO.DATA,
CLIENTES.CNOME,
AULAS.ANOME,
AULAS.DATA,
AULAS.VAGAS
FROM table1 INSCRICAO
left outer join table2 CLIENTES
on INSCRICAO.ID_INSCRICAO=CLIENTES.ID_CLIENTES
left outer join table3 AULAS
on AULAS.ID_AULA = INSCRICAO.ID_INSCRICAO;
That gives me error or multiplies the rows of tables, and the goal was to have the same number of records that the table entries
Can anyone help?