Is there such a thing as a join() aggregate function that concatentates field values at a specific character? - aggregate-functions

Let's say I have a table called cities with fields of state and city. Data looks like this:
State City
Ohio Eaton
Ohio Columbus
Ohio Dayton
Ohio Greenville
New York New York
New York Albany
New York Syracuse
I would like to be able to do this:
select state, join(city,',') from cities
group by state
...to return this:
State City
Ohio Eaton,Columbus,Dayton,Greenville
New York New York,Albany,Syracuse
Would I need to create some crazy UDF for this? If there's not a function, is there a way to apply some SQL magic to make this happen?

A recursive CTE should be able to accomplish this. I mocked up the sequence number to reset for each State. You may have to tweak this based on your actual table but it should at least get you thinking in the right direction. (Similar to what Marc B linked on the Teradata Forum but hopefully this is easier to read.)
WITH RECURSIVE city_list (state, cities, seq) AS
(
SELECT s.state
, s.city
, ROW_NUMBER() OVER (PARTITION BY State ORDER BY State, City) AS seq
FROM states s
QUALIFY seq = 1
UNION ALL
SELECT c.cities ||’, ’|| s.city
, ROW_NUMBER() OVER (ORDER BY State, City) AS seq
FROM city_list c, states s
WHERE s.seq = c.seq + 1
AND s.state = c.state
)
SELECT r.state, r.cities
FROM city_list r
WHERE r.seq = (SELECT MAX(h.seq) FROM city_list h
WHERE h.state = r.state
GROUP BY h.state)
;

Related

UNION not working Teradata SQL. Syntax error: Top N option is not allowed in a query connected by set operators

When I run both queries individually, they run correctly. But when I try to combine both result sets into one table using the UNION operator, it doesn't run and I get the error message : "Syntax error: Top N option is not allowed in a query connected by set operators."
select
top 1
city,
count(*)
from unicorns
where city is not null and industry = 'Edtech'
group by city
order by 2 desc
union
select
top 1
city,
count(*)
from unicorns
where city is not null and industry = 'Internet software & services'
group by city
order by 2 desc
I would appreciate any help,
Thanks.
Instead you can use window functions to achieve the same:
select
city,
count(*) ccount
from unicorns
where city is not null and industry = 'Edtech'
group by city
QUALIFY ROW_NUMBER() OVER (ORDER BY ccount DESC) = 1
union
select
city,
count(*) ccount
from unicorns
where city is not null and industry = 'Internet software & services'
group by city
QUALIFY ROW_NUMBER() OVER (ORDER BY ccount DESC) = 1
This way you aren't relying on ordering/top an interim result set (outside of partition ordering) and Teradata will be ok with it.
It's probably because the optimizer doesn't know if the 2nd ORDER BY is part of the top or the final ORDER BY of the UNION.
The common workaround for this type of error is to wrap the Selects in Derived Tables/CTEs:
select *
from
(
select
top 1
city,
count(*)
from unicorns
where city is not null and industry = 'Edtech'
group by city
order by 2 desc
) as dt
union
select *
from
(
select
top 1
city,
count(*)
from unicorns
where city is not null and industry = 'Internet software & services'
group by city
order by 2 desc
) as dt

Referencing a past query in a loop SQLite

I want to intersect two or more results from a query from a for loop
My code takes in strings from the command line and checks the database for movies with matching actors
movie database
id | name
actor database
id | name
acting
movie_id | actor_id
i.e.
inp = sys.argv[1]
query =
'''
SELECT m.name
FROM movie m
JOIN acting ag on m.id = ag.movie_id
JOIN actor a on a.id = ag.actor_id
WHERE a.name = ?
'''
cur.execute(query, (inp,))
for tup in cur.fetchall:
print(tup)
This program would get all the movies with actor called David
./program "David'
The Secret Life of Pets
The Big Short
Concussion
A Most Violent Year
Baggage Claim
Skyfall
Drive
Albert Nobbs
The Book of Eli
Shine a Light
The Bourne Ultimatum
The Simpsons Movie
I want to extend my program to take in multiple arguments, taking in multiple names of actors, where the actors act in the same movie.
Possible code?
for index in range(len(sys.argv - 1)):
# insert code here
I think I should use an intersection of the outputs of the queries, but I don't know how to do that.
This is the output of movies that both Albert and David
./program "Albert" "David"
A Most Violent Year
Baggage Claim
The Simpsons Movie
You can use aggregation to construct a query that returns the common movies of all actors that you pass as arguments:
query = """
SELECT m.name
FROM movie m
JOIN acting ag on m.id = ag.movie_id
JOIN actor a on a.id = ag.actor_id
WHERE ',' || ? || ',' LIKE '%,' || a.name || ',%'
GROUP BY m.id, m.name
HAVING COUNT(*) = ?
"""
cur = con.cursor()
cur.execute(query, (','.join(sys.argv[1:]), len(sys.argv)-1))
for tup in cur.fetchall():
print(tup[0])

Display records not matching in where clause

I need to display records not matching the where clause.
Example - select * from citytable where city in ('aa','bb','cc', 'dd','ee');
only aa, bb, cc are present in table, dd & ee are not present in the table. However, I still need to display dd & ee.
You are probably looking for something like this. An IN condition is the same as an inner join to a table containing the unique (distinct) values from the IN list. What you want is an outer join. You need to have a table instead of the IN list. In the solution below I show how you can create this "helper" table on the fly; there are several other methods, this just demonstrates the idea.
select deptno, ename from emp where deptno in (10, 50, 80);
DEPTNO ENAME
------ ------
10 CLARK
10 KING
10 MILLER
with h ( deptno ) as (
select 10 from dual union all
select 50 from dual union all
select 80 from dual
)
select h.deptno, e.ename
from h left outer join emp e
on h.deptno = e.deptno
;
DEPTNO ENAME
------ ------
10 CLARK
10 KING
10 MILLER
50
80
I'm not sure exactly how you want the output to look. If there is no data where city='ee', what exactly do you want to show? Something like this?
SELECT * FROM
(SELECT key AS A_key, one AS A_one, two AS A_two FROM cityTable WHERE one='aa') AS A
JOIN
(SELECT key AS E_key, one AS E_one, two AS E_two FROM cityTable WHERE one='ee') AS E
ON A_key=E_key
...etc.
Edit: or maybe this is it:
SELECT city FROM (SELECT city, count(*) AS c FROM cityTable GROUP BY city) WHERE c = 0
As i understand you said the 'dd' amd 'ee' are not present in the table but you still need it so you can achieve it using a union all. But remember that the columns of the 'dd' and 'ee' rows will always be null since there is no records present in your citytable
SELECT ct.col1 AS city, ct.col2.....<all columns of your table>
from citytable ct
where city in ('aa','bb','cc')
UNION ALL
select 'dd' as city,null ,null.....<nulls as many times as the number of columns of your table>
from citytable ct1
UNION ALL
select 'ee' as city,null ,null.....<nulls as many times as the number of columns of your table>
from citytable ct2

Sqlite - combining 2 SELECT statements from same table

I need to combine 2 results from SELECT statements that look in the same table.
What I have works but I'm sure there is a better way to do it.
SELECT
games._id,win.winner,deal.dealer
FROM
games,
(SELECT
players.name as winner
FROM
games, players
WHERE
players._id = games.winner
AND games._id = 2) AS win,
(SELECT
players.name as dealer
FROM
games, players
WHERE
players._id = games.dealer
AND games._id = 2) AS deal
WHERE
games._id = 2
Thanks for your help optimizing this query.
EDIT:
The schema for the tables are:
CREATE TABLE games
(
_id INTEGER PRIMARY KEY,
winner integer,
dealer integer
)
CREATE TABLE players
(
_id INTEGER PRIMARY KEY,
name text
)
Something like below(untested code) should work:
SELECT g._id,p1.name AS winner,p2.name AS dealer
FROM games AS g join players AS p1 ON p1._id = g.winner
JOIN players AS p2 on p2._id = g.dealer
WHERE g._id = 2

Dropdown list with a "Select All" option

I have three dropdown boxes, Region, District, and City. I want my District dropdown to have a "Select All" option so the user can get all Cities in the Region, else just display the City based on the selected District. My query looks like this:
IF #district =-2 THEN
(SELECT DISTINCT city
FROM myTable
WHERE RIGHT(Region, 3) = ?)
ORDER BY city)
ELSE
(select DISTINCT city
FROM myTable WHERE District = ?)
Order by city
I'm using vb.net/sql
I couldn't find any complex case scenarios in my search either.
Any sugguestions would be appreciated!
I am not really sure what your question is, but note that the query can simplified as follows:
SELECT DISTINCT city
FROM myTable
WHERE (#district = -2 and RIGHT(Region, 3) = ?)
or (#district <> -2 and District = ?)
ORDER BY city
2 ways, either append a select statement to your SQL, or add the option in the page_load using
if(!Page.IsPostBack)
{
DropDown1.Items.Insert(0, new ListItem("Select All", 0));
}

Resources