What (*) hides behind itself in this code - sql

I don't get why when I SELECT pizzeria_name and person_name in FROM nested query it doesn't work but when I put (*) instead i see two columns displayed on the screen with names person_name and pizzeria_name. How can i substitute (*) to see the same result?
SELECT ( SELECT person.name FROM person WHERE person.id = pv.person_id ) AS person_name,
( SELECT pizzeria.name FROM pizzeria WHERE pizzeria.id = pv.pizzeria_id ) AS pizzeria_name
FROM (
SELECT *
FROM person_visits
WHERE visit_date BETWEEN '2022-01-07' AND '2022-01-09'
) AS pv
ORDER BY person_name ASC, pizzeria_name DESC;
I tried everything pizzeria.id, pv.pizzeria_id etc but it doesn't work
Any types of Joins are prohibited
That's how my table is looks like
[1]: https://i.stack.imgur.com/vaWVB.png

Delete the subqueries and use a plain query:
select
person.name as person_name,
pizzeria.name as pizzeria_name
from person_visits
join person on person.id = person_visits.person_id
join pizzeria on pizzeria.id = person_visits.pizzeria_id
where visit_date between '2022-01-07' AND '2022-01-09'
order by 1, 2 desc
Standard naming convention of columns has been assumed.
If you absolutely must use subqueries:
select
(
select person.name
from person
where person.id = person_visits.person_id
) as person_name,
(
select pizzeria.name
from pizzeria
where pizzeria.id = person_visits.pizzeria_id
) as pizzeria_name
from person_visits
where visit_date between '2022-01-07' AND '2022-01-09'
order by 1, 2 desc

SELECT ( SELECT person.name FROM person WHERE person.id = pv.person_id ) AS person_name,
( SELECT pizzeria.name FROM pizzeria WHERE pizzeria.id = pv.pizzeria_id ) AS pizzeria_name
FROM (
SELECT person_id, pizzeria_id
FROM person_visits
WHERE visit_date BETWEEN '2022-01-07' AND '2022-01-09'
) AS pv
ORDER BY person_name ASC, pizzeria_name DESC;

Related

How to avg and then order data in SQL if it can appear in two columns?

So I have table points with columns like person1_id person2_id team_score and you can see that one person can appear in person1_id or person2_id column because the player can be in multiple teams, so the question is how do I get the top n players with highest average_score which is defined by the average of all the team_score he|she participated in? like person_id average_score?
One approach uses a union to create a single logical column of all players and their scores:
SELECT
person_id,
AVG(team_score) AS average_score
FROM
(
SELECT person1_id AS person_id, team_score FROM points
UNION ALL
SELECT person2_id, team_score FROM points
) t
GROUP BY
person_id
ORDER BY
AVG(team_score) DESC
LIMIT 10; -- e.g. for the top 10, but you may replace 10 with any value you want
I think Tim's answer is a very good answer. But, assuming that you have a persons table, you can do this without union all:
select p.person_id,
(select avg(team_score)
from points po
where p.person_id in (po.person1_id, po.person2_id)
) as average_score
from persons p
order by average_score desc
limit 5; -- or whatever
A rather more complicated expression is probably the most efficient:
select p.person_id,
( (select sum(team_score)
from points po
where p.person_id = po.person1_id
) +
(select sum(team_score)
from points po
where p.person_id = po.person2_id
)
) /
nullif( (select count(*)
from points po
where p.person_id = po.person1_id
) +
(select count(*)
from points po
where p.person_id = po.person2_id
), 0
) as average_score
from persons p
order by average_score desc
limit 5;
The reason this is more efficient is that it can make use of indexes on points(person1_id, team_score) and points(person2_id, team_score).
You might solve your problem with a coalesce function, something like:
SELECT
COALESCE(person1_id, person2_id) AS person_id,
AVG(team_score) as average_score
FROM points
GROUP BY COALESCE(person1_id, person2_id)
ORDER BY AVG(team_score)
What's going on here is COALESCE(col1, col2) returns the first non-null column in the list. You can do this with as many columns as you like.
Here are the docs: https://www.sqlite.org/lang_corefunc.html#coalesce
First you need to get all the distinct palyers and then join them to the points table:
select
d.id person_id,
avg(p.team_score) avgscore
from (
select person1_id id from points
union
select person2_id id from points
) d inner join points p
on (p.person1_id = d.id) or (p.person2_id = d.id)
group by d.id
order by avgscore desc
limit 3
See the demo

Pulling rows with SQL MAXDATE

I'm trying to run a query from a HR table. I'm bringing in all employees and their dependents who share the same 'Primary_Key_Value'. My statement works but I'm getting duplicates because some dependents have multiple MED_COV_EFFECTIVE_DATEs. I need to bring in only the lastest or MAX date. When I try to use the MAX(MED_COV_EFFECTIVE_DATE) function, I'm getting errors. Can someone please help me?
SELECT DISTINCT PRIMARY_KEY_VALUE, RECORD_ID, LAST_NAME, FIRST_NAME, DATE_OF_BIRTH, HIRE_DATE,
RELATIONSHIP_CODE, MED_COV_EFFECTIVE_DATE, SOCIAL_SECURITY_NUMBER
FROM COVERAGE_TABLE T1
WHERE T1.PRIMARY_KEY_VALUE IN
(
SELECT T2.PRIMARY_KEY_VALUE
FROM COVERAGE_TABLE T2
WHERE T2.HIRE_DATE IS NOT NULL
)
ORDER BY PRIMARY_KEY_VALUE, RECORD_ID
Dang, wasn't thinking about inner select can only return 1 column earlier. Try something like this:
SELECT T2.PRIMARY_KEY_VALUE, MAX(T2.Med_Cov_Effective_Date)
INTO #MostRecentCoveredKeys
FROM COVERAGE_TABLE T2
WHERE T2.HIRE_DATE IS NOT NULL
GROUP BY T2.Primary_Key_Value
This should give you a unique set of Primary_Key_Values.
Or CTE Version:
; WITH MostRecentCoveredKeys
AS
SELECT T2.PRIMARY_KEY_VALUE, MAX(T2.Med_Cov_Effective_Date)
FROM COVERAGE_TABLE T2
WHERE T2.HIRE_DATE IS NOT NULL
GROUP BY T2.Primary_Key_Value
Then JOIN the original table and cte (or temp table) like so:
SELECT PRIMARY_KEY_VALUE, RECORD_ID, LAST_NAME, FIRST_NAME, DATE_OF_BIRTH,
HIRE_DATE, RELATIONSHIP_CODE, MED_COV_EFFECTIVE_DATE,
SOCIAL_SECURITY_NUMBER
FROM COVERAGE_TABLE T1
INNER JOIN MostRecentCoveredKeys mrck
ON mrck.Primary_Key_Value = T1.Primary_Key_Value
ORDER BY T1.PRIMARY_KEY_VALUE, T1.RECORD_ID
--you need to include the '#' in front of table name
--on join if using the temp table version
--DROP TABLE #MostRecentCoveredKeys
This query will fetch the latest data:
SELECT B.PRIMARY_KEY_VALUE, B.RECORD_ID, B.LAST_NAME, B.FIRST_NAME,
B.DATE_OF_BIRTH, B.HIRE_DATE, B.RELATIONSHIP_CODE,
B.MED_COV_EFFECTIVE_DATE, B.SOCIAL_SECURITY_NUMBER
FROM
(SELECT PRIMARY_KEY_VALUE, MAX(MED_COV_EFFECTIVE_DATE) MAX_DATE
FROM COVERAGE_TABLE
WHERE HIRE_DATE IS NOT NULL
GROUP BY PRIMARY_KEY_VALUE) A INNER JOIN
(SELECT * FROM COVERAGE_TABLE
WHERE HIRE_DATE IS NOT NULL) B
ON A.PRIMARY_KEY_VALUE=B.PRIMARY_KEY_VALUE AND A.MAX_DATE=B.MED_COV_EFFECTIVE_DATE;
;with a as
(
select
*
,row_number() over(partition by PRIMARY_KEY_VALUE, order by Med_Cov_Effective_Date desc) rn
FROM COVERAGE_TABLE T1
WHERE HIRE_DATE IS NOT NULL
)
select *
from a
where rn=1
ORDER BY PRIMARY_KEY_VALUE, RECORD_ID

SQL code it's looks to complicate

Test Table
create table Test (
Id integer,
Store_N varchar(25),
Department varchar(25)
);
INSERT INTO Test (Id, Store_N, Department )
Values (25,'1','A'), (67,'1','A'), (34,'1','A'), (97,'1','C'),
(21,'1','C'), (268,'1','B'), (456,'2','A'), (349,'2','A'),
(935,'2','B'), (36,'3','B'), (637,'3','B'), (388,'3','B'),
(891,'3','B'), (344,'4','A'), (763,'4','A'), (836,'4','A')
SELECT * , ROW_NUMBER() OVER( Partition BY Store_N ORDER BY Store_N ) AS AA
FROM Test;
Result is
I need to exclude all stores which have only one department and have the only DISTINCT department for each store. The result looks like this
And this is code
SELECT DISTINCT TB4.Department, TB4.Store_N
From
(
SELECT TB0.Store_N, TB0.Department FROM Test TB0
INNER JOIN
(
SELECT TB2.Store_N , Count(*) AS AA1
FROM
(
SELECT DISTINCT TB1.Department , TB1.Store_N
FROM
( SELECT * , ROW_NUMBER() OVER( Partition BY Store_N ORDER BY Store_N ) AA
FROM Test ) TB1
) TB2
group by TB2.Store_N
HAVING
COUNT(*) > 1 ) TB3
ON TB0.Store_N = TB3.Store_N
) TB4
Now the question how to simplify this code?
Thank you
You can basically do:
select store_n, department
from test
group by store_n, department;
But, you want to exclude stores that have only one department, so lets do a count:
select store_n, department
from (select store_n, department, count(*) over (partition by store_n) as cnt
from test
group by store_n, department
) t
where cnt > 1;
Here is a SQL Fiddle.
You are going a long way round to get the functionality of the "GROUP BY" clause
SELECT TB2.Store_N , TB2.Department
FROM
(
SELECT Department , Store_N, count(Id) as c
FROM Test
GROUP BY Department, Store_N) as TB2
WHERE TB2.c > 1

Sql query to fetch minimum date start against each employee

I have two table asg and work rship
In work rship table there is date_start for each employee. For few employee date_start is duplicate so I have to choose the min(date_start) from work rship table
for this i wrote a query:
SELECT assignment_name,
REGEXP_SUBSTR(ASSIGNMENT_NAME, '[0-9]+') PERSON_NUMBER,
NVL( wrk.date_start,t.effective_start_date) ,
NVL( WRK.WORKER_TYPE,'E'),
NVL( WRK.LEGAL_EMPLOYER_NAME, 'N/A')
FROM
(SELECT apps.assignment_table.*,
COUNT(*) OVER (PARTITION BY assignment_name, effective_start_date, effective_end_date, effective_latest_change) AS c
FROM apps.assignment_table
) T
LEFT OUTER JOIN
(SELECT *
FROM apps.work_table
WHERE date_start =
(SELECT MIN(date_start) FROM apps.work_table
)
) wrk
ON regexp_substr(t.assignment_name, '[0-9]+')=wrk.person_number
WHERE C =1;
But in the above query I did a mistake of just selecting select min(date_start) from apps.work_table this means min(date_start) from the entire table.
Instead of this I should have included the regexp_substr(t.assignment_name, '[0-9]+')=wrk.person_number inside the inline query itself.
But now when I am including it.. it's not working.
LEFT OUTER JOIN
(SELECT *
FROM apps.work_table
WHERE date_start =
(SELECT MIN(date_start) FROM apps.work_table
)
) wrk
ON
Unless the start_date for the person is the minimum value across all people in the entire table (and not just the minimum date for this person) then the code above will not find any rows that will match the person you want.
What you probably meant to do is something like:
LEFT OUTER JOIN
( SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( PARTITION BY person_number ORDER BY date_start ASC ) AS rn
FROM apps.work_table t
)
WHERE rn = 1
) wrk
ON

SQL group function nested too deeply

I want to make a SQL query which finds the pname of parts which are the least repeated in supplier_parts_shipment.
Table 1 supplier (sno, sname, city)
1, ahmad, jeddah
2,kaled,med
3,njwa,med
Table 2 parts (pno, pname, color)
1, laptop, red
2,keybord,blue
Table 3 supplier_parts_shipment (shno, sno, pno, date)
1,1,1,2014
2,2,1,2014
3,3,2,2014
I tried something like this:
SELECT pname
, min(count(pno))
FROM parts
WHERE pno IN (SELECT pno
FROM supplier_parts_shipment
group by
pname
HAVING min(count(pno))
)
SQL> /
pno IN(SELECT pno FROM supplier_parts_shipment group by pname HAVING min(count(pno))))
*
ERROR at line 2:
ORA-00935: group function is nested too deeply
I would have gone about it in a different manner.
First create a query that shows the counts of shipments by pname ordered in ascending values. Use that as a subquery and pick the first.
SELECT * FROM (
SELECT COUNT(sps.pno), p.pname
FROM supplier_parts_shipment sps
JOIN parts p on sps.pno = p.pno
GROUP BY pname
ORDER BY COUNT(sps.pno) ASC)
WHERE ROWNUM = 1
If there are multiple parts which are least frequent and you want all of them then:
WITH pno_frequencies AS (
SELECT pno,
COUNT(1) AS pno_cnt
FROM supplier_parts_shipment
GROUP BY pno
),
least_frequent_pnos AS (
SELECT pno
FROM pno_frequencies
WHERE pno_cnt = ( SELECT MIN( pno_cnt ) FROM pno_frequencies )
)
SELECT pname
FROM parts p
WHERE EXISTS (SELECT 1
FROM least_frequent_pnos f
WHERE p.pno = f.pno
);
If you only want a single part regardless of whether there are multiple parts with the same minimum frequency then:
WITH pno_frequencies AS (
SELECT pno,
COUNT(1) AS pno_cnt
FROM supplier_parts_shipment
GROUP BY pno
ORDER BY pno_cnt ASC
),
least_frequent_pno AS (
SELECT pno
FROM pno_frequencies
WHERE ROWNUM = 1
)
SELECT pname
FROM parts p
WHERE EXISTS (SELECT 1
FROM least_frequent_pno f
WHERE p.pno = f.pno
);
SQLFIDDLE
min(count(pno))
makes no sense. that is why you are getting the error. try:
select parts.pname
, subse.c
from (select pno
, dense_rank() over (order by c asc) r
, c
from (select pno
, count(pno) as c
from supplier_parts_shipment
group by
pno
)
) subse
inner join parts
on (parts.pno = subse.pno)
where subse.r = 1
the innermost select counts the supplier_parts_shipment for pno, the second level finds the pno that has the least count from the innermost. the outermost select then joins pname from parts and filters to the one that has the least repeats.
If you are using oracle 12c or higher then it will be quite easy with row limiting clause as following:
Select p.pname, count(1) as cnt
From parts p
Join supplier_parts_shipment sps
On sps.pno = p.pno
Group by p.name
Order by cnt
Fetch first row with ties
For more information about row limiting clause refer this document.
Cheers!!