Snowflake Unable to get the hierarchy columns values - snowflake-cloud-data-platform

I have below table from which i am trying to get the correspondent manager name against the employee
TITLE EMPLOYEE_ID MANAGER_ID
President 1
Vice President Engineering 10 1
Programmer 100 10
QA Engineer 101 10
Vice President HR 20 1
Health Insurance Analyst 200 20
i used below hierarchy query to get the result
select employee_id, manager_id, title, prior report_title
from employees
start with title = 'President'
connect by
manager_id = prior employee_id
order by employee_id;
But result not returning as i expected
Expected:
EMPLOYEE_ID MANAGER_ID title report_title
10 1 Vice President Engineering President
Can anyone help on this?

If you use a recursive CTE, you can get the output you want.
with emptree as
(select employee_id, title, manager_id, null as report_title
from employees
where manager_id is null
union all
select employees.employee_id, employees.title, employees.manager_id, emptree.title
from employees
join emptree
on employees.manager_id = emptree.employee_id
)
select employee_id, manager_id, title, report_title
from emptree
order by employee_id;
EMPLOYEE_ID
MANAGER_ID
TITLE
REPORT_TITLE
1
NULL
President
10
1
Vice President Engineering
President
20
1
Vice President HR
President
100
10
Programmer
Vice President Engineering
101
10
QA Engineer
Vice President Engineering
200
20
Health Insurance Analyst
Vice President HR

Related

Get last diploma for each employee

I want to get the last diploma for each employee :
SELECT * FROM (SELECT e.employeeid,afd.AdminFileId ,afd.Title,ss.Name,YearObtained,afd.CreateDate,
ROW_NUMBER() OVER (PARTITION BY afd.AdminFileId ORDER BY afd.CreateDate desc) AS rn
FROM AF_Degree afd
LEFT JOIN AF_AdminFile aaf ON afd.AdminFileId = aaf.AdminFileId
LEFT JOIN schools_School ss ON afd.SchoolId = ss.ID
LEFT JOIN employee e ON e.adminfileid=aaf.AdminFileId) AS D WHERE D.employeeid=109
The result of the above query :
Case of EmployeeId= 109 :
employeeid AdminFileId Title School YearObtained CreateDate
107 149971 Intercambio universitario; Programa Erasmus ( meses) Universidad Politécnica de Cartagena 2008 2018-05-14 03:45:41.6436995
107 149971 Student exchange Umeå University 2008 2018-06-27 16:01:53.8213765
107 149971 Erasmus Program (12months) POLITECNICA CARTAGENA 2006 2018-06-27 16:01:53.8213765
Case of EmployeeId= 139 :
employeeid AdminFileId Title School YearObtained CreateDate
139 145555 Electronic Business Engineering Czech University of Life Sciences Prague 2007 2018-05-14 03:45:41.6436995
139 145555 Entrepreneurship and Management Umeå University 2009 2015-06-23 17:30:31.3100000
139 145555 Ingeniería técnica en informática de gestión Czech University of Life Sciences Prague 2009 2015-06-23 17:30:31.3100000
For EmoloyeeId=109 the expected result is :
EmployeeId AdminFileId Title School YearObtained CreateDate
107 149971 Student exchange Umeå University 2008 2018-06-27 16:01:53.8213765
For EmoloyeeId=139 the expected result is :
EmployeeId AdminFileId Title
139 7198 Ingeniería técnica en informática de gestión Czech University of Life Sciences Prague 2009 2015-06-23 17:30:31.3100000
How to get the last diploma obtained for an employee based on the YearObtained and the CreateDate especially when we have two diplomas in the same year and having the same CreateDate like in the two cases mentioned above and their related expected output ?
Just add WHERE d.rn = 1 to the outer query. Also may need to change the partition just a bit to ... ORDER BY YearObtained DESC, afd.CreateDate DESC)...
SELECT *
FROM (
SELECT e.employeeid,afd.AdminFileId ,afd.Title,ss.Name,YearObtained,afd.CreateDate,
ROW_NUMBER() OVER (PARTITION BY afd.AdminFileId ORDER BY afd.CreateDate desc) AS rn
FROM AF_Degree afd
LEFT JOIN AF_AdminFile aaf ON afd.AdminFileId = aaf.AdminFileId
LEFT JOIN schools_School ss ON afd.SchoolId = ss.ID
LEFT JOIN employee e ON e.adminfileid=aaf.AdminFileId
) AS D
WHERE d.rn = 1
That will get you one row. However, if there's the same YearObtained and CreateDate then it's not guaranteed which record you will get. You may need to add a third column to the ORDER BY in the partition such as an ID or something unique.

To Display a Stock Details

I am trying to display the stock details like MRP, Sales Rate , Tax Amount and so on.
I used three grid views to make a entry in my form. They are,
GV Purchase
GV Product Details - (It is used to show the product name and product code )
GV Stock Details - (It is used to show the Quantity, MRP, Sales Price and so on)
I used SQL Query for populate the DB records in my grid view.
I select a Product A from Product Grid view in my form ,the Stock grid will show the corresponding data of the Product A
My DB records,
code Name QTY MRP S.Rate
aa11 Pro A 5 120.00 130.00
aa11 Pro A 2 130.00 150.00
aa12 Pro B 4 100.00 110.00
aa13 Pro C 2 50.00 60.00
When I select Pro A in GV Product Details in my form. The GV Stock Details will be shown the QTY, MRP, S.Rate for the Pro A
But My Query returns like this format
aa11 Pro A 5 120.00 130.00
2 130.00 150.00
4 100.00 110.00
2 50.00 60.00
This is my Query,
select s.*,iif( d.NewSalePrice is null,s.saleprice1,d.NewSalePrice)as NewSalePrice,Pdate from (select s.*,p.ProductFullName,p.ProductCode from Stock s,Product p where s.productfullcode=p.ProductFullCode) s left join(select Productfullcode,MRP,PUnitPrice,NewSalePrice,Pdate from DailyPricing ) d on s.ProductFullCode=d.ProductFullCode where s.MRP=d.MRP and s.UnitPrice=d.PUnitPrice and Pdate=(select MAX(Pdate) from DailyPricing where PUnitPrice=s.UnitPrice and mrp=s.MRP and ProductFullCode=s.ProductFullCode) order by ProductFullCode
How to I get Stock details only matched by Pro A
Note : These table format is just a model for my Table
Thanks in Advance,
Vinayak vk.:-)
You could probably simplify your query, and add a where clause for the product name you need.
Haven't tested it against mock data, but something like this SQL:
select
s.*,
p.ProductFullName,
p.ProductCode,
coalesce(d.NewSalePrice, s.saleprice1) as SalePrice,
max(d.Pdate) over (partition by p.ProductFullCode, s.mrp, s.UnitPrice) as MaxPdate
from Product p
join Stock s on s.productfullcode = p.ProductFullCode
join DailyPricing d on (s.ProductFullCode = d.ProductFullCode and s.MRP = d.MRP and s.UnitPrice = d.PUnitPrice)
where p.ProductFullName = 'Pro A'
order by p.ProductFullCode

SQL query to get all the data from different tables with same id

Sorry if this is too elemental but I cannot work it out. Don’t know how to search information on it either:
I have three tables:
Provider
id_provider name
---------- -----------
100 John
101 Sam
102 Peter
Contact
id_contact RowNo Email
---------- ----------- ----------------
100 1 john#work.com
100 2 john#gmail.com
101 1 sam#work.com
101 2 sam#yahoo.com
Product
Id_product RowNo Product
---------- ----------- ------------------------
100 1 John’s 1st product
100 2 John’s 2nd product
101 1 Sam’s 1st product
101 2 Sam’s 2nd product
101 3 Sam’s 3rd product
I need a query to show all the data from the three tables like this:
Id name id_contact RowNo Email Id_Product RowNo Product
100 John 100 1 john#work.com 100 1 John’s 1st product
100 John 100 2 john#gmail.com 100 2 John’s 2st product
101 Sam 101 1 sam#work.com 101 1 Sam's 1st product
101 Sam 101 2 sam#yahoo.com 101 2 Sam's 2nd product
101 Sam null null null 101 3 Sam's 3rd product
102 Peter null null null null null null
I am trying all the joins I know but I cannot make it work.
Thanks a lot
You can use the following query:
SELECT t1.id_provider AS Id, t1.name,
t2.id_contact, t2.cRowNo, t2.Email,
t2.Id_product, t2.Product
FROM Provider AS t1
LEFT JOIN (
SELECT COALESCE(id_contact, id_product) AS id,
c.id_contact, c.RowNo AS cRowNo, c.Email,
p.Id_product, p.Product, p.RowNo AS pRowNo
FROM Contact AS c
FULL JOIN Product AS p ON p.id_product = c.id_contact AND p.RowNo = c.RowNo
) AS t2 ON t1.id_provider = t2.id
The query does a FULL JOIN between Contact and Product tables and joins the table derived from the FULL JOIN to Provider table.
A FULL JOIN is required because we cannot know beforehand which of the two tables, Contact or Product, contains the most rows for each id.
select *
from Provider P1
left join Contact C2
on C2.id_contact = P1.id_provider
left join Product P2
on P2.id_product = P1.id_provider
SELECT prov.*,
c.*,
prod.*
FROM PROVIDER prov
LEFT JOIN Product prod ON prod.id_product = prov.id_provider
LEFT JOIN Contact c ON prov.id_provider = c.id_contact
AND prod.RowNo = c.RowNo
use left joins but join provider to product first then to contact
SQL Fiddle Demo

sql server 2012 merge values from two tables

I have two tables
tblA(sn, ID int pk, name varchar(50), amountA decimal(18,2))
and
tblB(ID int fk, amountB decimal(18,2))
here: tblA occures only once and tblB may occure multiple time
I need the query to display data like:
sn ID name AmountA amountB Balance
1 1001 abc 5000.00 5000.00
2 1002 xyz 10000.00
1002 4000.00 6000.00 (AmountA-AmountB)
3 1003 pqr 15000.00
1003 4000.00
1003 3000.00
1003 2000.00 6000.00 (AmountA-sum(AmountB))
Please ask if any confusion
I tried using lag and lead function but I couldnot get the desire result, Please help.
Since you are using SQL Server 2012, you can use a partition with an aggregate function (SUM):
SELECT t.sn,
t.ID,
t.name,
t.credits AS AmountA,
t.debits AS amountB,
SUM(t.credits - t.debits) OVER (PARTITION BY t.ID ORDER BY t.debits, t.credits) AS Balance
FROM
(
SELECT sn,
ID,
name,
AmountA AS credits,
0 AS debits
FROM tblA
UNION ALL
SELECT 0 AS sn,
ID,
NULL AS name,
0 AS credits,
amountB AS debits
FROM tblB
) t
ORDER BY t.ID,
t.debits,
t.credits
Explanation:
Since the records in tables A and B each represent a single transaction (i.e. a credit or debit), using a UNION query to bring both sets of data into a single table works well here. After this, I compute a rolling sum using the difference between credit and debit, for each record, for each ID partition group. The ordering is chosen such that credits appear at the top of each partition while debits appear on the bottom.

SQL query like GROUP BY with OR condition

I'll try to describe the real situation. In our company we have a reservation system with a table, let's call it Customers, where e-mail and phone contacts are saved with each incoming order - that's the part of a system I can't change. I'm facing the problem how to get count of unique customers. With the unique customer I mean group of people who has either the same e-mail or same phone number.
Example 1: From the real life you can imagine Tom and Sandra who are married. Tom, who ordered 4 products, filled in our reservation system 3 different e-mail addresses and 2 different phone numbers when one of them shares with Sandra (as a homephone) so I can presume they are connected somehow. Sandra except this shared phone number filled also her private one and for both orders she used only one e-mail address. For me this means to count all of the following rows as one unique customer. So in fact this unique customer may grow up into the whole family.
ID E-mail Phone Comment
---- ------------------- -------------- ------------------------------
0 tom#email.com +44 111 111 First row
1 tommy#email.com +44 111 111 Same phone, different e-mail
2 thomas#email.com +44 111 111 Same phone, different e-mail
3 thomas#email.com +44 222 222 Same e-mail, different phone
4 sandra#email.com +44 222 222 Same phone, different e-mail
5 sandra#email.com +44 333 333 Same e-mail, different phone
As ypercube said I will probably need a recursion to count all of these unique customers.
Example 2: Here is the example of what I want to do.Is it possible to get count of unique customers without using recursion for instance by using cursor or something or is the recursion necessary ?
ID E-mail Phone Comment
---- ------------------- -------------- ------------------------------
0 linsey#email.com +44 111 111 ─┐
1 louise#email.com +44 111 111 ├─ 1. unique customer
2 louise#email.com +44 222 222 ─┘
---- ------------------- -------------- ------------------------------
3 steven#email.com +44 333 333 ─┐
4 steven#email.com +44 444 444 ├─ 2. unique customer
5 sandra#email.com +44 444 444 ─┘
---- ------------------- -------------- ------------------------------
6 george#email.com +44 555 555 ─── 3. unique customer
---- ------------------- -------------- ------------------------------
7 xavier#email.com +44 666 666 ─┐
8 xavier#email.com +44 777 777 ├─ 4. unique customer
9 xavier#email.com +44 888 888 ─┘
---- ------------------- -------------- ------------------------------
10 robert#email.com +44 999 999 ─┐
11 miriam#email.com +44 999 999 ├─ 5. unique customer
12 sherry#email.com +44 999 999 ─┘
---- ------------------- -------------- ------------------------------
----------------------------------------------------------------------
Result ∑ = 5 unique customers
----------------------------------------------------------------------
I've tried a query with GROUP BY but I don't know how to group the result by either first or second column. I'm looking for let's say something like
SELECT COUNT(*) FROM Customers
GROUP BY Email OR Phone
Thanks again for any suggestions
P.S.
I really appreciate the answers for this question before the complete rephrase. Now the answers here may not correspond to the update so please don't downvote here if you're going to do it (except the question of course :). I completely rewrote this post.Thanks and sorry for my wrong start.
Here is a full solution using a recursive CTE.
;WITH Nodes AS
(
SELECT DENSE_RANK() OVER (ORDER BY Part, PartRank) SetId
, [ID]
FROM
(
SELECT [ID], 1 Part, DENSE_RANK() OVER (ORDER BY [E-mail]) PartRank
FROM dbo.Customer
UNION ALL
SELECT [ID], 2, DENSE_RANK() OVER (ORDER BY Phone) PartRank
FROM dbo.Customer
) A
),
Links AS
(
SELECT DISTINCT A.Id, B.Id LinkedId
FROM Nodes A
JOIN Nodes B ON B.SetId = A.SetId AND B.Id < A.Id
),
Routes AS
(
SELECT DISTINCT Id, Id LinkedId
FROM dbo.Customer
UNION ALL
SELECT DISTINCT Id, LinkedId
FROM Links
UNION ALL
SELECT A.Id, B.LinkedId
FROM Links A
JOIN Routes B ON B.Id = A.LinkedId AND B.LinkedId < A.Id
),
TransitiveClosure AS
(
SELECT Id, Id LinkedId
FROM Links
UNION
SELECT LinkedId Id, LinkedId
FROM Links
UNION
SELECT Id, LinkedId
FROM Routes
),
UniqueCustomers AS
(
SELECT Id, MIN(LinkedId) UniqueCustomerId
FROM TransitiveClosure
GROUP BY Id
)
SELECT A.Id, A.[E-mail], A.Phone, B.UniqueCustomerId
FROM dbo.Customer A
JOIN UniqueCustomers B ON B.Id = A.Id
Finding groups that have only same Phone:
SELECT
ID
, Name
, Phone
, DENSE_RANK() OVER (ORDER BY Phone) AS GroupPhone
FROM
MyTable
ORDER BY
GroupPhone
, ID
Finding groups that have only same Name:
SELECT
ID
, Name
, Phone
, DENSE_RANK() OVER (ORDER BY Name) AS GroupName
FROM
MyTable
ORDER BY
GroupName
, ID
Now, for the (complex) query you describe, let's say we have a table like this instead:
ID Name Phone
---- ------------- -------------
0 Kate +44 333 333
1 Sandra +44 000 000
2 Thomas +44 222 222
3 Robert +44 000 000
4 Thomas +44 444 444
5 George +44 222 222
6 Kate +44 000 000
7 Robert +44 444 444
--------------------------------
Should all these be in one group? As they all share name or phone with someone else, forming a "chain" of relative persons:
0-6 same name
6-1-3 same phone
3-7 same name
7-4 same-phone
4-2 same name
2-5 bame phone
For the dataset in the example you could write something like this:
;WITH Temp AS (
SELECT Name, Phone,
DENSE_RANK() OVER (ORDER BY Name) AS NameGroup,
DENSE_RANK() OVER (ORDER BY Phone) AS PhoneGroup
FROM MyTable)
SELECT MAX(Phone), MAX(Name), COUNT(*)
FROM Temp
GROUP BY NameGroup, PhoneGroup
I don't know if this is the best solution, but here it is:
SELECT
MyTable.ID, MyTable.Name, MyTable.Phone,
CASE WHEN N.No = 1 AND P.No = 1 THEN 1
WHEN N.No = 1 AND P.No > 1 THEN 2
WHEN N.No > 1 OR P.No > 1 THEN 3
END as GroupRes
FROM
MyTable
JOIN (SELECT Name, count(Name) No FROM MyTable GROUP BY Name) N on MyTable.Name = N.Name
JOIN (SELECT Phone, count(Phone) No FROM MyTable GROUP BY Phone) P on MyTable.Phone = P.Phone
The problem is that here are some joins made on varchars and could end up in increasing execution time.
Here is my solution:
SELECT p.LastName, P.FirstName, P.HomePhone,
CASE
WHEN ph.PhoneCount=1 THEN
CASE
WHEN n.NameCount=1 THEN 'unique name and phone'
ELSE 'common name'
END
ELSE
CASE
WHEN n.NameCount=1 THEN 'common phone'
ELSE 'common phone and name'
END
END
FROM Contacts p
INNER JOIN
(SELECT HomePhone, count(LastName) as PhoneCount
FROM Contacts
GROUP BY HomePhone) ph ON ph.HomePhone = p.HomePhone
INNER JOIN
(SELECT FirstName, count(LastName) as NameCount
FROM Contacts
GROUP BY FirstName) n ON n.FirstName = p.FirstName
LastN FirstN Phone Comment
Hoover Brenda 8138282334 unique name and phone
Washington Brian 9044563211 common name
Roosevelt Brian 7737653279 common name
Reagan Charles 7734567869 unique name and phone

Resources