SQL fill in redundant values to table - sql

I want to take the following table...
City
Company
Revenue
New York
A
400
New York
B
300
Singapore
B
400
Washington D.C.
C
400
London
D
400
and produce the below version.
City
Company
Present
Revenue
New York
A
1
400
New York
B
1
300
New York
C
0
0
New York
D
0
0
Singapore
A
0
0
Singapore
B
1
400
Singapore
C
0
0
Singapore
D
0
0
...
...
London
D
1
400
So, basically filling extra company values to encompass the entire dataset, adding a 1 in the "Present" field if they are present, otherwise zero...
I hope my question makes sense!

You can pull this off by first making a result set that has every combination of company and city. A cross join will do the trick here:
SELECT companies.company, cities.city
FROM (SELECT DISTINCT Company FROM yourtable) companies,
(SELECT DISTINCT City FROM yourtable) cities
We can now LEFT JOIN from that result set into your table to get to the final result set:
WITH all_values AS
(
SELECT companies.company, cities.city
FROM (SELECT DISTINCT Company FROM yourtable) companies,
(SELECT DISTINCT City FROM yourtable) cities
)
SELECT all_values.company,
all_values.city,
CASE WHEN yourtable.company IS NOT NULL THEN 1 ELSE 0 END as Present,
yourtable.Revenue
FROM
all_values
LEFT OUTER JOIN yourtable
ON all_values.company = yourtable.company
AND all_values.city = yourtable.city;

select city.city
, company.company
, coalesce(t.Revenue, 0)
, case when t.revenue is not null then 1 else 0 end as Present
from (select distinct company from tablename) company
cross join (select distinct City from tablename) city
left join tablename t
on t.city = city.city
and t.company = company.company

Related

Find rows in which a column value only occurs once (Single-Sided Entries in Double Entry accounting system)

I have a table of bank transactions, AccountTransaction, and rows with for e.g.
Amount
Payee_Name
Transaction_ID
Is_Corresponding_Transaction
69.00
Bob Jones
1
1
-69.00
Bob Jones
1
0
25.00
Bill
2
1
-25.00
Bill
2
0
297.00
Sally
3
1
-5.00
Ted
4
1
2.50
Ted
4
0
2.50
Ted
4
0
How do I select only (all) TS like Sally's where the Transaction ID only occurs once?
Bonus points: How do I select TS like Ted's where the sum of all Is_Corresponding_Transaction = 0 != the sum of Is_Corresponding_Transaction = 1 for a given TS_ID?
I was looking and found a Group by or where not exists, but couldn't figure out how to get that to work
Here's an e.g. of what I tried:
select
Full_Name, amount, a.Posted_Date,a.Payee_Name, a.Memo, Accounts.Account_Name
from AccountTransaction a
left join Accounts on Accounts.Account_Code = a.Account_Code
left join users on a.UserId = users.UserId
where not exists (select 1 from AccountTransaction b where a.Transaction_ID = b.Transaction_ID having count(*)>1)
and a.Pending= 0
ORDER by a.Posted_Date desc
Just to expand on Stu's comment. Here is one option that uses the window function
with cte as (
Select *
,NetSum = sum(Amount) over (partition by Transaction_ID)
,NetCnt = sum(1) over (partition by Transaction_ID)
From YourTable
)
Select *
From cte
Where NetSum<>0
or NetCnt<>2

PostreSQL filter results by subset of a joined table and group them

I have table of people, another table of cars and a third table to join them since they have a many to many relationship. I want to select people who own a certain set of cars and group them by a region property on the person. So for example I would want to find all American's who own a Honda and a Nissan.
Example:
people table
id name region
1 Jon America
2 Jane Europe
3 Mike America
cars table
id make
1 Honda
2 Toyota
3 Nissan
people_cars table
person_id car_id
1 1
1 3
2 2
3 1
Desired result:
region own_honda_and_nissan
America 1
Europe 0
An idea for a SQL expression I have is:
SELECT
people.region,
CASE WHEN SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2 THEN 1 ELSE 0 AS own_honda_and_nissan
FROM people
JOIN people_cars ON people_cars.person_id = people.id
JOIN cars ON people_cars.car_id = cars.id
GROUP BY people.region
HAVING
SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2
ORDER BY own_honda_and_nissan DESC
This works if you group by people.id but once they get grouped by region it no longer works.
Use two levels of aggregation:
SELECT p.pregion, COUNT(*) as own_honda_and_nissan
FROM (SELECT pid, p.region,
FROM people p JOIN
people_cars pc
ON pc.person_id = p.id JOIN
cars c
ON pc.car_id = c.id
WHERE c.name IN ('Honda', 'Nissan')
GROUP BY p.id, p.region
HAVING COUNT(DISTINCT c.name) = 2
) p
GROUP BY p.region
ORDER BY own_honda_and_nissan DESC

SQL aggregation to add new column with flag

I have a column with
Country
-------
Canada
India
USA
India
China
Canada
I want to update this table by inserting another column called M_U which can only have 0 or 1
If country occurs more than once = 1
If country occurs only once = 0
output
-------
Canada 1
India 1
USA 0
India 1
China 0
Canada 1
This should work for you:
select a.country, case when b.c >1 then 1 else 0 end
from countries a
join (
select Country, count(*) as c from countries group by Country
) b on b.country = a.country
You should use windows functions for this:
select t.*,
(case when count(*) over (partition by country) > 1 then 1 else 0 end) as flag
from t;
This is essential a_horse_with_no_name's answer. I'll delete it if that answer is undeleted.

Trying to count particular column from three different tables

Master table
SerNo HospitalId CityId
1 1 1
2 1 1
3 2 2
4 3 2
5 1 1
HospitalMaster
HospitalId HospitalName
1 ABC
2 XYZ
CityMaster
CityId City
1 Delhi
2 Bombay
Result
I need something like this
City TotalHospital
Delhi 1
Bombay 2
I tried joining the tables but I keep getting the total rows of the columns and not of the hospitals.
Thank you.
Left join the city master table to a subquery which finds the hospital counts for each city. Note carefully that we only count distinct hospitals, because a hospital city relationship may appear more than once in the master table.
SELECT t1.City, COALESCE(t2.cnt, 0) AS TotalHospital
FROM CityMaster t1
LEFT JOIN
(
SELECT CityId, COUNT(DISTINCT HospitalId) cnt
FROM Master
GROUP BY CityID
) t2
ON t1.CityId = t2.CityId;
Demo
Try this:
SELECT C.City,COUNT(DISTINCT HospitalID)TotalHospital
FROM CityMaster C
JOIN Master_table M ON M.CityId=C.CityId
GROUP BY C.City
You could apply join
select M.City,count(distinct M.HospitalId) from CityMaster C inner join Master M ON C.CityId = M.CityId
group by M.City
You can do it with using JOIN
Just replace #city, #hospital, #table with your table names.
select C.City,T.CityId from #city C,#hosp H,#table T WHERE T.CityId = C.CityId AND T.HospitalId = H.HospitalId Group by C.City,T.CityId
As we need city name along with count, we can get by join city master and master tables.
select max(C.cityname), count(distinct M.HospitalId)
from CityMaster C
inner join Master M
on C.Cityid = M.CityId
group by M.cityid

Last Record Of Each Group Using Multiple Joins In Sql Server

I Have 3 tables Customer, Bank and BankTransaction.
On My View I want to display each customer with their Balance in the bank account.
Here is my tables
Customer
Id Name
---------
1 John
2 Jack
Bank
Id CustomerId BankName
----------------------------------
1 1 HSBC
2 2 HSBC
BankTransaction
Id BankID MoneyIn MoneyOut Balance
---------------------------------------------
1 1 1000 0 1000
2 1 0 500 500
3 2 2000 0 2000
4 2 2000 0 4000
5 2 1000 0 5000
Now I want to Display following data view query
John 500
Jack 5000
Last Balance of each customer
Try this
SELECT A.Name,
Sum(C.MoneyIN) - Sum(C.MoneyOut) AS Balance
FROM #Customer A
JOIN #Bank B ON A.Id = B.id
JOIN #BankTransaction C ON B.Id = C.BankID
GROUP BY A.Name
Using Window function you can get the result. Try this.
;WITH cte
AS (SELECT Row_number() OVER (partition BY b.id ORDER BY a.id DESC) rn,
c.Name,
a.balance
FROM BankTransaction a
JOIN bank b ON a.BankID = b.Id
JOIN Customer c ON c.Id = b.CustomerId)
SELECT name, balance
FROM cte
WHERE rn = 1