pratham0011 commited on
Commit
e619571
·
verified ·
1 Parent(s): c287648

Upload 9 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.12
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy the current directory contents into the container at /app
8
+ COPY . /app
9
+
10
+ # Install system dependencies
11
+ RUN apt-get update && apt-get install -y \
12
+ build-essential \
13
+ curl \
14
+ software-properties-common \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ # Install Python dependencies
18
+ RUN pip install --no-cache-dir -r requirements.txt
19
+
20
+ # Make port 7860 available to the world outside this container
21
+ EXPOSE 7860
22
+
23
+ # Create a script to run both FastAPI and Streamlit
24
+ RUN echo '#!/bin/bash\n\
25
+ uvicorn main:app --host 0.0.0.0 --port 8000 &\n\
26
+ streamlit run streamlit_app.py --server.port 7860 --server.address 0.0.0.0\n\
27
+ ' > /app/run.sh
28
+
29
+ RUN chmod +x /app/run.sh
30
+
31
+ # Run the script when the container launches
32
+ CMD ["/app/run.sh"]
main.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # main.py
2
+ from fastapi import FastAPI, HTTPException
3
+ from pydantic import BaseModel
4
+ import psycopg2
5
+ from psycopg2.extras import RealDictCursor
6
+ import os
7
+ from dotenv import load_dotenv
8
+ import google.generativeai as genai
9
+
10
+ app = FastAPI()
11
+
12
+ # Load environment variables and configure Genai
13
+ load_dotenv()
14
+ genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
15
+
16
+ class Query(BaseModel):
17
+ question: str
18
+
19
+ def get_gemini_response(question, prompt):
20
+ model = genai.GenerativeModel('gemini-1.5-pro')
21
+ response = model.generate_content([prompt, question])
22
+ return response.text.strip() # Added strip() to remove any extra whitespace
23
+
24
+ sql_prompt = """
25
+ Convert the following English question to a PostgreSQL query for the Pagila DVD rental database.
26
+ Only return the SQL query without any markdown formatting or explanations.
27
+ The database has these main tables:
28
+ - actor (actor_id, first_name, last_name)
29
+ - film (film_id, title, description, release_year, rental_rate, length, rating)
30
+ - category (category_id, name)
31
+ - film_category (film_id, category_id)
32
+ - inventory (inventory_id, film_id, store_id)
33
+ - rental (rental_id, rental_date, inventory_id, customer_id, return_date, staff_id)
34
+ - customer (customer_id, first_name, last_name, email)
35
+ - payment (payment_id, customer_id, staff_id, rental_id, amount, payment_date)
36
+
37
+ Example queries:
38
+ Q: List all actors
39
+ A: SELECT * FROM actor;
40
+
41
+ Q: Show top 10 most rented movies
42
+ A: SELECT f.title, COUNT(r.rental_id) as rental_count FROM film f JOIN inventory i ON f.film_id = i.film_id JOIN rental r ON i.inventory_id = r.inventory_id GROUP BY f.title ORDER BY rental_count DESC LIMIT 10;
43
+ """
44
+
45
+ def execute_sql_query(query):
46
+ conn = None
47
+ try:
48
+ conn = psycopg2.connect(
49
+ dbname=os.getenv('DB_NAME'),
50
+ user=os.getenv('DB_USER'),
51
+ password=os.getenv('DB_PASSWORD'),
52
+ host=os.getenv('DB_HOST'),
53
+ port=os.getenv('DB_PORT', '5432')
54
+ )
55
+ with conn.cursor(cursor_factory=RealDictCursor) as cursor:
56
+ cursor.execute(query)
57
+ result = cursor.fetchall()
58
+ return result
59
+ except Exception as e:
60
+ raise HTTPException(status_code=400, detail=f"Database Error: {str(e)}")
61
+ finally:
62
+ if conn:
63
+ conn.close()
64
+
65
+ @app.post("/query")
66
+ async def process_query(query: Query):
67
+ try:
68
+ sql_query = get_gemini_response(query.question, sql_prompt)
69
+ # Remove any SQL code block markers if present
70
+ sql_query = sql_query.replace('```sql', '').replace('```', '').strip()
71
+ result = execute_sql_query(sql_query)
72
+ return {"query": sql_query, "result": result}
73
+ except Exception as e:
74
+ raise HTTPException(status_code=400, detail=str(e))
pagila/1. pagila-schema.sql ADDED
@@ -0,0 +1,1544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --
2
+ -- PostgreSQL database dump
3
+ --
4
+
5
+ -- Dumped from database version 9.6.3
6
+ -- Dumped by pg_dump version 10beta1
7
+
8
+ SET statement_timeout = 0;
9
+ SET lock_timeout = 0;
10
+ SET idle_in_transaction_session_timeout = 0;
11
+ SET client_encoding = 'UTF8';
12
+ SET standard_conforming_strings = on;
13
+ SET check_function_bodies = false;
14
+ SET client_min_messages = warning;
15
+ SET row_security = off;
16
+
17
+ --
18
+ -- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
19
+ --
20
+
21
+ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
22
+
23
+
24
+ --
25
+ -- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
26
+ --
27
+
28
+ COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
29
+
30
+
31
+ SET search_path = public, pg_catalog;
32
+
33
+ --
34
+ -- Name: mpaa_rating; Type: TYPE; Schema: public; Owner: postgres
35
+ --
36
+
37
+ CREATE TYPE mpaa_rating AS ENUM (
38
+ 'G',
39
+ 'PG',
40
+ 'PG-13',
41
+ 'R',
42
+ 'NC-17'
43
+ );
44
+
45
+
46
+ ALTER TYPE mpaa_rating OWNER TO postgres;
47
+
48
+ --
49
+ -- Name: year; Type: DOMAIN; Schema: public; Owner: postgres
50
+ --
51
+
52
+ CREATE DOMAIN year AS integer
53
+ CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));
54
+
55
+
56
+ ALTER DOMAIN year OWNER TO postgres;
57
+
58
+ --
59
+ -- Name: _group_concat(text, text); Type: FUNCTION; Schema: public; Owner: postgres
60
+ --
61
+
62
+ CREATE FUNCTION _group_concat(text, text) RETURNS text
63
+ LANGUAGE sql IMMUTABLE
64
+ AS $_$
65
+ SELECT CASE
66
+ WHEN $2 IS NULL THEN $1
67
+ WHEN $1 IS NULL THEN $2
68
+ ELSE $1 || ', ' || $2
69
+ END
70
+ $_$;
71
+
72
+
73
+ ALTER FUNCTION public._group_concat(text, text) OWNER TO postgres;
74
+
75
+ --
76
+ -- Name: film_in_stock(integer, integer); Type: FUNCTION; Schema: public; Owner: postgres
77
+ --
78
+
79
+ CREATE FUNCTION film_in_stock(p_film_id integer, p_store_id integer, OUT p_film_count integer) RETURNS SETOF integer
80
+ LANGUAGE sql
81
+ AS $_$
82
+ SELECT inventory_id
83
+ FROM inventory
84
+ WHERE film_id = $1
85
+ AND store_id = $2
86
+ AND inventory_in_stock(inventory_id);
87
+ $_$;
88
+
89
+
90
+ ALTER FUNCTION public.film_in_stock(p_film_id integer, p_store_id integer, OUT p_film_count integer) OWNER TO postgres;
91
+
92
+ --
93
+ -- Name: film_not_in_stock(integer, integer); Type: FUNCTION; Schema: public; Owner: postgres
94
+ --
95
+
96
+ CREATE FUNCTION film_not_in_stock(p_film_id integer, p_store_id integer, OUT p_film_count integer) RETURNS SETOF integer
97
+ LANGUAGE sql
98
+ AS $_$
99
+ SELECT inventory_id
100
+ FROM inventory
101
+ WHERE film_id = $1
102
+ AND store_id = $2
103
+ AND NOT inventory_in_stock(inventory_id);
104
+ $_$;
105
+
106
+
107
+ ALTER FUNCTION public.film_not_in_stock(p_film_id integer, p_store_id integer, OUT p_film_count integer) OWNER TO postgres;
108
+
109
+ --
110
+ -- Name: get_customer_balance(integer, timestamp with time zone); Type: FUNCTION; Schema: public; Owner: postgres
111
+ --
112
+
113
+ CREATE FUNCTION get_customer_balance(p_customer_id integer, p_effective_date timestamp with time zone) RETURNS numeric
114
+ LANGUAGE plpgsql
115
+ AS $$
116
+ --#OK, WE NEED TO CALCULATE THE CURRENT BALANCE GIVEN A CUSTOMER_ID AND A DATE
117
+ --#THAT WE WANT THE BALANCE TO BE EFFECTIVE FOR. THE BALANCE IS:
118
+ --# 1) RENTAL FEES FOR ALL PREVIOUS RENTALS
119
+ --# 2) ONE DOLLAR FOR EVERY DAY THE PREVIOUS RENTALS ARE OVERDUE
120
+ --# 3) IF A FILM IS MORE THAN RENTAL_DURATION * 2 OVERDUE, CHARGE THE REPLACEMENT_COST
121
+ --# 4) SUBTRACT ALL PAYMENTS MADE BEFORE THE DATE SPECIFIED
122
+ DECLARE
123
+ v_rentfees DECIMAL(5,2); --#FEES PAID TO RENT THE VIDEOS INITIALLY
124
+ v_overfees INTEGER; --#LATE FEES FOR PRIOR RENTALS
125
+ v_payments DECIMAL(5,2); --#SUM OF PAYMENTS MADE PREVIOUSLY
126
+ BEGIN
127
+ SELECT COALESCE(SUM(film.rental_rate),0) INTO v_rentfees
128
+ FROM film, inventory, rental
129
+ WHERE film.film_id = inventory.film_id
130
+ AND inventory.inventory_id = rental.inventory_id
131
+ AND rental.rental_date <= p_effective_date
132
+ AND rental.customer_id = p_customer_id;
133
+
134
+ SELECT COALESCE(SUM(IF((rental.return_date - rental.rental_date) > (film.rental_duration * '1 day'::interval),
135
+ ((rental.return_date - rental.rental_date) - (film.rental_duration * '1 day'::interval)),0)),0) INTO v_overfees
136
+ FROM rental, inventory, film
137
+ WHERE film.film_id = inventory.film_id
138
+ AND inventory.inventory_id = rental.inventory_id
139
+ AND rental.rental_date <= p_effective_date
140
+ AND rental.customer_id = p_customer_id;
141
+
142
+ SELECT COALESCE(SUM(payment.amount),0) INTO v_payments
143
+ FROM payment
144
+ WHERE payment.payment_date <= p_effective_date
145
+ AND payment.customer_id = p_customer_id;
146
+
147
+ RETURN v_rentfees + v_overfees - v_payments;
148
+ END
149
+ $$;
150
+
151
+
152
+ ALTER FUNCTION public.get_customer_balance(p_customer_id integer, p_effective_date timestamp with time zone) OWNER TO postgres;
153
+
154
+ --
155
+ -- Name: inventory_held_by_customer(integer); Type: FUNCTION; Schema: public; Owner: postgres
156
+ --
157
+
158
+ CREATE FUNCTION inventory_held_by_customer(p_inventory_id integer) RETURNS integer
159
+ LANGUAGE plpgsql
160
+ AS $$
161
+ DECLARE
162
+ v_customer_id INTEGER;
163
+ BEGIN
164
+
165
+ SELECT customer_id INTO v_customer_id
166
+ FROM rental
167
+ WHERE return_date IS NULL
168
+ AND inventory_id = p_inventory_id;
169
+
170
+ RETURN v_customer_id;
171
+ END $$;
172
+
173
+
174
+ ALTER FUNCTION public.inventory_held_by_customer(p_inventory_id integer) OWNER TO postgres;
175
+
176
+ --
177
+ -- Name: inventory_in_stock(integer); Type: FUNCTION; Schema: public; Owner: postgres
178
+ --
179
+
180
+ CREATE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean
181
+ LANGUAGE plpgsql
182
+ AS $$
183
+ DECLARE
184
+ v_rentals INTEGER;
185
+ v_out INTEGER;
186
+ BEGIN
187
+ -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
188
+ -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
189
+
190
+ SELECT count(*) INTO v_rentals
191
+ FROM rental
192
+ WHERE inventory_id = p_inventory_id;
193
+
194
+ IF v_rentals = 0 THEN
195
+ RETURN TRUE;
196
+ END IF;
197
+
198
+ SELECT COUNT(rental_id) INTO v_out
199
+ FROM inventory LEFT JOIN rental USING(inventory_id)
200
+ WHERE inventory.inventory_id = p_inventory_id
201
+ AND rental.return_date IS NULL;
202
+
203
+ IF v_out > 0 THEN
204
+ RETURN FALSE;
205
+ ELSE
206
+ RETURN TRUE;
207
+ END IF;
208
+ END $$;
209
+
210
+
211
+ ALTER FUNCTION public.inventory_in_stock(p_inventory_id integer) OWNER TO postgres;
212
+
213
+ --
214
+ -- Name: last_day(timestamp with time zone); Type: FUNCTION; Schema: public; Owner: postgres
215
+ --
216
+
217
+ CREATE FUNCTION last_day(timestamp with time zone) RETURNS date
218
+ LANGUAGE sql IMMUTABLE STRICT
219
+ AS $_$
220
+ SELECT CASE
221
+ WHEN EXTRACT(MONTH FROM $1) = 12 THEN
222
+ (((EXTRACT(YEAR FROM $1) + 1) operator(pg_catalog.||) '-01-01')::date - INTERVAL '1 day')::date
223
+ ELSE
224
+ ((EXTRACT(YEAR FROM $1) operator(pg_catalog.||) '-' operator(pg_catalog.||) (EXTRACT(MONTH FROM $1) + 1) operator(pg_catalog.||) '-01')::date - INTERVAL '1 day')::date
225
+ END
226
+ $_$;
227
+
228
+
229
+ ALTER FUNCTION public.last_day(timestamp with time zone) OWNER TO postgres;
230
+
231
+ --
232
+ -- Name: last_updated(); Type: FUNCTION; Schema: public; Owner: postgres
233
+ --
234
+
235
+ CREATE FUNCTION last_updated() RETURNS trigger
236
+ LANGUAGE plpgsql
237
+ AS $$
238
+ BEGIN
239
+ NEW.last_update = CURRENT_TIMESTAMP;
240
+ RETURN NEW;
241
+ END $$;
242
+
243
+
244
+ ALTER FUNCTION public.last_updated() OWNER TO postgres;
245
+
246
+ --
247
+ -- Name: customer_customer_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
248
+ --
249
+
250
+ CREATE SEQUENCE customer_customer_id_seq
251
+ START WITH 1
252
+ INCREMENT BY 1
253
+ NO MINVALUE
254
+ NO MAXVALUE
255
+ CACHE 1;
256
+
257
+
258
+ ALTER TABLE customer_customer_id_seq OWNER TO postgres;
259
+
260
+ SET default_tablespace = '';
261
+
262
+ SET default_with_oids = false;
263
+
264
+ --
265
+ -- Name: customer; Type: TABLE; Schema: public; Owner: postgres
266
+ --
267
+
268
+ CREATE TABLE customer (
269
+ customer_id SERIAL PRIMARY KEY,
270
+ store_id smallint NOT NULL,
271
+ first_name text NOT NULL,
272
+ last_name text NOT NULL,
273
+ email text,
274
+ address_id smallint NOT NULL,
275
+ activebool boolean DEFAULT true NOT NULL,
276
+ create_date date DEFAULT ('now'::text)::date NOT NULL,
277
+ last_update timestamp with time zone DEFAULT now(),
278
+ active integer
279
+ );
280
+
281
+
282
+ ALTER TABLE customer OWNER TO postgres;
283
+
284
+ --
285
+ -- Name: rewards_report(integer, numeric); Type: FUNCTION; Schema: public; Owner: postgres
286
+ --
287
+
288
+ CREATE FUNCTION rewards_report(min_monthly_purchases integer, min_dollar_amount_purchased numeric) RETURNS SETOF customer
289
+ LANGUAGE plpgsql SECURITY DEFINER
290
+ AS $_$
291
+ DECLARE
292
+ last_month_start DATE;
293
+ last_month_end DATE;
294
+ rr RECORD;
295
+ tmpSQL TEXT;
296
+ BEGIN
297
+
298
+ /* Some sanity checks... */
299
+ IF min_monthly_purchases = 0 THEN
300
+ RAISE EXCEPTION 'Minimum monthly purchases parameter must be > 0';
301
+ END IF;
302
+ IF min_dollar_amount_purchased = 0.00 THEN
303
+ RAISE EXCEPTION 'Minimum monthly dollar amount purchased parameter must be > $0.00';
304
+ END IF;
305
+
306
+ last_month_start := CURRENT_DATE - '3 month'::interval;
307
+ last_month_start := to_date((extract(YEAR FROM last_month_start) || '-' || extract(MONTH FROM last_month_start) || '-01'),'YYYY-MM-DD');
308
+ last_month_end := LAST_DAY(last_month_start);
309
+
310
+ /*
311
+ Create a temporary storage area for Customer IDs.
312
+ */
313
+ CREATE TEMPORARY TABLE tmpCustomer (customer_id INTEGER NOT NULL PRIMARY KEY);
314
+
315
+ /*
316
+ Find all customers meeting the monthly purchase requirements
317
+ */
318
+
319
+ tmpSQL := 'INSERT INTO tmpCustomer (customer_id)
320
+ SELECT p.customer_id
321
+ FROM payment AS p
322
+ WHERE DATE(p.payment_date) BETWEEN '||quote_literal(last_month_start) ||' AND '|| quote_literal(last_month_end) || '
323
+ GROUP BY customer_id
324
+ HAVING SUM(p.amount) > '|| min_dollar_amount_purchased || '
325
+ AND COUNT(customer_id) > ' ||min_monthly_purchases ;
326
+
327
+ EXECUTE tmpSQL;
328
+
329
+ /*
330
+ Output ALL customer information of matching rewardees.
331
+ Customize output as needed.
332
+ */
333
+ FOR rr IN EXECUTE 'SELECT c.* FROM tmpCustomer AS t INNER JOIN customer AS c ON t.customer_id = c.customer_id' LOOP
334
+ RETURN NEXT rr;
335
+ END LOOP;
336
+
337
+ /* Clean up */
338
+ tmpSQL := 'DROP TABLE tmpCustomer';
339
+ EXECUTE tmpSQL;
340
+
341
+ RETURN;
342
+ END
343
+ $_$;
344
+
345
+
346
+ ALTER FUNCTION public.rewards_report(min_monthly_purchases integer, min_dollar_amount_purchased numeric) OWNER TO postgres;
347
+
348
+ --
349
+ -- Name: group_concat(text); Type: AGGREGATE; Schema: public; Owner: postgres
350
+ --
351
+
352
+ CREATE AGGREGATE group_concat(text) (
353
+ SFUNC = _group_concat,
354
+ STYPE = text
355
+ );
356
+
357
+
358
+ ALTER AGGREGATE public.group_concat(text) OWNER TO postgres;
359
+
360
+ --
361
+ -- Name: actor_actor_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
362
+ --
363
+
364
+ CREATE SEQUENCE actor_actor_id_seq
365
+ START WITH 1
366
+ INCREMENT BY 1
367
+ NO MINVALUE
368
+ NO MAXVALUE
369
+ CACHE 1;
370
+
371
+
372
+ ALTER TABLE actor_actor_id_seq OWNER TO postgres;
373
+
374
+ --
375
+ -- Name: actor; Type: TABLE; Schema: public; Owner: postgres
376
+ --
377
+
378
+ CREATE TABLE actor (
379
+ actor_id integer DEFAULT nextval('actor_actor_id_seq'::regclass) NOT NULL,
380
+ first_name text NOT NULL,
381
+ last_name text NOT NULL,
382
+ last_update timestamp with time zone DEFAULT now() NOT NULL
383
+ );
384
+
385
+
386
+ ALTER TABLE actor OWNER TO postgres;
387
+
388
+ --
389
+ -- Name: category_category_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
390
+ --
391
+
392
+ CREATE SEQUENCE category_category_id_seq
393
+ START WITH 1
394
+ INCREMENT BY 1
395
+ NO MINVALUE
396
+ NO MAXVALUE
397
+ CACHE 1;
398
+
399
+
400
+ ALTER TABLE category_category_id_seq OWNER TO postgres;
401
+
402
+ --
403
+ -- Name: category; Type: TABLE; Schema: public; Owner: postgres
404
+ --
405
+
406
+ CREATE TABLE category (
407
+ category_id integer DEFAULT nextval('category_category_id_seq'::regclass) NOT NULL,
408
+ name text NOT NULL,
409
+ last_update timestamp with time zone DEFAULT now() NOT NULL
410
+ );
411
+
412
+
413
+ ALTER TABLE category OWNER TO postgres;
414
+
415
+ --
416
+ -- Name: film_film_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
417
+ --
418
+
419
+ CREATE SEQUENCE film_film_id_seq
420
+ START WITH 1
421
+ INCREMENT BY 1
422
+ NO MINVALUE
423
+ NO MAXVALUE
424
+ CACHE 1;
425
+
426
+
427
+ ALTER TABLE film_film_id_seq OWNER TO postgres;
428
+
429
+ --
430
+ -- Name: film; Type: TABLE; Schema: public; Owner: postgres
431
+ --
432
+
433
+ CREATE TABLE film (
434
+ film_id integer DEFAULT nextval('film_film_id_seq'::regclass) NOT NULL,
435
+ title text NOT NULL,
436
+ description text,
437
+ release_year year,
438
+ language_id smallint NOT NULL,
439
+ original_language_id smallint,
440
+ rental_duration smallint DEFAULT 3 NOT NULL,
441
+ rental_rate numeric(4,2) DEFAULT 4.99 NOT NULL,
442
+ length smallint,
443
+ replacement_cost numeric(5,2) DEFAULT 19.99 NOT NULL,
444
+ rating mpaa_rating DEFAULT 'G'::mpaa_rating,
445
+ last_update timestamp with time zone DEFAULT now() NOT NULL,
446
+ special_features text[],
447
+ fulltext tsvector NOT NULL
448
+ );
449
+
450
+
451
+ ALTER TABLE film OWNER TO postgres;
452
+
453
+ --
454
+ -- Name: film_actor; Type: TABLE; Schema: public; Owner: postgres
455
+ --
456
+
457
+ CREATE TABLE film_actor (
458
+ actor_id smallint NOT NULL,
459
+ film_id smallint NOT NULL,
460
+ last_update timestamp with time zone DEFAULT now() NOT NULL
461
+ );
462
+
463
+
464
+ ALTER TABLE film_actor OWNER TO postgres;
465
+
466
+ --
467
+ -- Name: film_category; Type: TABLE; Schema: public; Owner: postgres
468
+ --
469
+
470
+ CREATE TABLE film_category (
471
+ film_id smallint NOT NULL,
472
+ category_id smallint NOT NULL,
473
+ last_update timestamp with time zone DEFAULT now() NOT NULL
474
+ );
475
+
476
+
477
+ ALTER TABLE film_category OWNER TO postgres;
478
+
479
+ --
480
+ -- Name: actor_info; Type: VIEW; Schema: public; Owner: postgres
481
+ --
482
+
483
+ CREATE VIEW actor_info AS
484
+ SELECT a.actor_id,
485
+ a.first_name,
486
+ a.last_name,
487
+ group_concat(DISTINCT (((c.name)::text || ': '::text) || ( SELECT group_concat((f.title)::text) AS group_concat
488
+ FROM ((film f
489
+ JOIN film_category fc_1 ON ((f.film_id = fc_1.film_id)))
490
+ JOIN film_actor fa_1 ON ((f.film_id = fa_1.film_id)))
491
+ WHERE ((fc_1.category_id = c.category_id) AND (fa_1.actor_id = a.actor_id))
492
+ GROUP BY fa_1.actor_id))) AS film_info
493
+ FROM (((actor a
494
+ LEFT JOIN film_actor fa ON ((a.actor_id = fa.actor_id)))
495
+ LEFT JOIN film_category fc ON ((fa.film_id = fc.film_id)))
496
+ LEFT JOIN category c ON ((fc.category_id = c.category_id)))
497
+ GROUP BY a.actor_id, a.first_name, a.last_name;
498
+
499
+
500
+ ALTER TABLE actor_info OWNER TO postgres;
501
+
502
+ --
503
+ -- Name: address_address_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
504
+ --
505
+
506
+ CREATE SEQUENCE address_address_id_seq
507
+ START WITH 1
508
+ INCREMENT BY 1
509
+ NO MINVALUE
510
+ NO MAXVALUE
511
+ CACHE 1;
512
+
513
+
514
+ ALTER TABLE address_address_id_seq OWNER TO postgres;
515
+
516
+ --
517
+ -- Name: address; Type: TABLE; Schema: public; Owner: postgres
518
+ --
519
+
520
+ CREATE TABLE address (
521
+ address_id integer DEFAULT nextval('address_address_id_seq'::regclass) NOT NULL,
522
+ address text NOT NULL,
523
+ address2 text,
524
+ district text NOT NULL,
525
+ city_id smallint NOT NULL,
526
+ postal_code text,
527
+ phone text NOT NULL,
528
+ last_update timestamp with time zone DEFAULT now() NOT NULL
529
+ );
530
+
531
+
532
+ ALTER TABLE address OWNER TO postgres;
533
+
534
+ --
535
+ -- Name: city_city_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
536
+ --
537
+
538
+ CREATE SEQUENCE city_city_id_seq
539
+ START WITH 1
540
+ INCREMENT BY 1
541
+ NO MINVALUE
542
+ NO MAXVALUE
543
+ CACHE 1;
544
+
545
+
546
+ ALTER TABLE city_city_id_seq OWNER TO postgres;
547
+
548
+ --
549
+ -- Name: city; Type: TABLE; Schema: public; Owner: postgres
550
+ --
551
+
552
+ CREATE TABLE city (
553
+ city_id integer DEFAULT nextval('city_city_id_seq'::regclass) NOT NULL,
554
+ city text NOT NULL,
555
+ country_id smallint NOT NULL,
556
+ last_update timestamp with time zone DEFAULT now() NOT NULL
557
+ );
558
+
559
+
560
+ ALTER TABLE city OWNER TO postgres;
561
+
562
+ --
563
+ -- Name: country_country_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
564
+ --
565
+
566
+ CREATE SEQUENCE country_country_id_seq
567
+ START WITH 1
568
+ INCREMENT BY 1
569
+ NO MINVALUE
570
+ NO MAXVALUE
571
+ CACHE 1;
572
+
573
+
574
+ ALTER TABLE country_country_id_seq OWNER TO postgres;
575
+
576
+ --
577
+ -- Name: country; Type: TABLE; Schema: public; Owner: postgres
578
+ --
579
+
580
+ CREATE TABLE country (
581
+ country_id integer DEFAULT nextval('country_country_id_seq'::regclass) NOT NULL,
582
+ country text NOT NULL,
583
+ last_update timestamp with time zone DEFAULT now() NOT NULL
584
+ );
585
+
586
+
587
+ ALTER TABLE country OWNER TO postgres;
588
+
589
+ --
590
+ -- Name: customer_list; Type: VIEW; Schema: public; Owner: postgres
591
+ --
592
+
593
+ CREATE VIEW customer_list AS
594
+ SELECT cu.customer_id AS id,
595
+ (((cu.first_name)::text || ' '::text) || (cu.last_name)::text) AS name,
596
+ a.address,
597
+ a.postal_code AS "zip code",
598
+ a.phone,
599
+ city.city,
600
+ country.country,
601
+ CASE
602
+ WHEN cu.activebool THEN 'active'::text
603
+ ELSE ''::text
604
+ END AS notes,
605
+ cu.store_id AS sid
606
+ FROM (((customer cu
607
+ JOIN address a ON ((cu.address_id = a.address_id)))
608
+ JOIN city ON ((a.city_id = city.city_id)))
609
+ JOIN country ON ((city.country_id = country.country_id)));
610
+
611
+
612
+ ALTER TABLE customer_list OWNER TO postgres;
613
+
614
+ --
615
+ -- Name: film_list; Type: VIEW; Schema: public; Owner: postgres
616
+ --
617
+
618
+ CREATE VIEW film_list AS
619
+ SELECT film.film_id AS fid,
620
+ film.title,
621
+ film.description,
622
+ category.name AS category,
623
+ film.rental_rate AS price,
624
+ film.length,
625
+ film.rating,
626
+ group_concat((((actor.first_name)::text || ' '::text) || (actor.last_name)::text)) AS actors
627
+ FROM ((((category
628
+ LEFT JOIN film_category ON ((category.category_id = film_category.category_id)))
629
+ LEFT JOIN film ON ((film_category.film_id = film.film_id)))
630
+ JOIN film_actor ON ((film.film_id = film_actor.film_id)))
631
+ JOIN actor ON ((film_actor.actor_id = actor.actor_id)))
632
+ GROUP BY film.film_id, film.title, film.description, category.name, film.rental_rate, film.length, film.rating;
633
+
634
+
635
+ ALTER TABLE film_list OWNER TO postgres;
636
+
637
+ --
638
+ -- Name: inventory_inventory_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
639
+ --
640
+
641
+ CREATE SEQUENCE inventory_inventory_id_seq
642
+ START WITH 1
643
+ INCREMENT BY 1
644
+ NO MINVALUE
645
+ NO MAXVALUE
646
+ CACHE 1;
647
+
648
+
649
+ ALTER TABLE inventory_inventory_id_seq OWNER TO postgres;
650
+
651
+ --
652
+ -- Name: inventory; Type: TABLE; Schema: public; Owner: postgres
653
+ --
654
+
655
+ CREATE TABLE inventory (
656
+ inventory_id integer DEFAULT nextval('inventory_inventory_id_seq'::regclass) NOT NULL,
657
+ film_id smallint NOT NULL,
658
+ store_id smallint NOT NULL,
659
+ last_update timestamp with time zone DEFAULT now() NOT NULL
660
+ );
661
+
662
+
663
+ ALTER TABLE inventory OWNER TO postgres;
664
+
665
+ --
666
+ -- Name: language_language_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
667
+ --
668
+
669
+ CREATE SEQUENCE language_language_id_seq
670
+ START WITH 1
671
+ INCREMENT BY 1
672
+ NO MINVALUE
673
+ NO MAXVALUE
674
+ CACHE 1;
675
+
676
+
677
+ ALTER TABLE language_language_id_seq OWNER TO postgres;
678
+
679
+ --
680
+ -- Name: language; Type: TABLE; Schema: public; Owner: postgres
681
+ --
682
+
683
+ CREATE TABLE language (
684
+ language_id integer DEFAULT nextval('language_language_id_seq'::regclass) NOT NULL,
685
+ name character(20) NOT NULL,
686
+ last_update timestamp with time zone DEFAULT now() NOT NULL
687
+ );
688
+
689
+
690
+ ALTER TABLE language OWNER TO postgres;
691
+
692
+ --
693
+ -- Name: nicer_but_slower_film_list; Type: VIEW; Schema: public; Owner: postgres
694
+ --
695
+
696
+ CREATE VIEW nicer_but_slower_film_list AS
697
+ SELECT film.film_id AS fid,
698
+ film.title,
699
+ film.description,
700
+ category.name AS category,
701
+ film.rental_rate AS price,
702
+ film.length,
703
+ film.rating,
704
+ group_concat((((upper("substring"((actor.first_name)::text, 1, 1)) || lower("substring"((actor.first_name)::text, 2))) || upper("substring"((actor.last_name)::text, 1, 1))) || lower("substring"((actor.last_name)::text, 2)))) AS actors
705
+ FROM ((((category
706
+ LEFT JOIN film_category ON ((category.category_id = film_category.category_id)))
707
+ LEFT JOIN film ON ((film_category.film_id = film.film_id)))
708
+ JOIN film_actor ON ((film.film_id = film_actor.film_id)))
709
+ JOIN actor ON ((film_actor.actor_id = actor.actor_id)))
710
+ GROUP BY film.film_id, film.title, film.description, category.name, film.rental_rate, film.length, film.rating;
711
+
712
+
713
+ ALTER TABLE nicer_but_slower_film_list OWNER TO postgres;
714
+
715
+ --
716
+ -- Name: payment_payment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
717
+ --
718
+
719
+ CREATE SEQUENCE payment_payment_id_seq
720
+ START WITH 1
721
+ INCREMENT BY 1
722
+ NO MINVALUE
723
+ NO MAXVALUE
724
+ CACHE 1;
725
+
726
+
727
+ ALTER TABLE payment_payment_id_seq OWNER TO postgres;
728
+
729
+ --
730
+ -- Name: payment; Type: TABLE; Schema: public; Owner: postgres
731
+ --
732
+
733
+ CREATE TABLE payment (
734
+ payment_id integer DEFAULT nextval('payment_payment_id_seq'::regclass) NOT NULL,
735
+ customer_id smallint NOT NULL,
736
+ staff_id smallint NOT NULL,
737
+ rental_id integer NOT NULL,
738
+ amount numeric(5,2) NOT NULL,
739
+ payment_date timestamp with time zone NOT NULL
740
+ ) PARTITION BY RANGE(payment_date);
741
+
742
+ ALTER TABLE payment OWNER TO postgres;
743
+
744
+ --
745
+ -- Name: payment_p2017_01; Type: TABLE; Schema: public; Owner: postgres
746
+ --
747
+
748
+ CREATE TABLE payment_p2017_01 PARTITION OF payment
749
+ FOR VALUES FROM ('2017-01-01 00:00:00+3:00') TO ('2017-02-01 00:00:00+3:00');
750
+
751
+ ALTER TABLE payment_p2017_01 OWNER TO postgres;
752
+
753
+ --
754
+ -- Name: payment_p2017_02; Type: TABLE; Schema: public; Owner: postgres
755
+ --
756
+
757
+ CREATE TABLE payment_p2017_02 PARTITION OF payment
758
+ FOR VALUES FROM ('2017-02-01 00:00:00+3:00') TO ('2017-03-01 00:00:00+3:00');
759
+
760
+ ALTER TABLE payment_p2017_02 OWNER TO postgres;
761
+
762
+ --
763
+ -- Name: payment_p2017_03; Type: TABLE; Schema: public; Owner: postgres
764
+ --
765
+
766
+ CREATE TABLE payment_p2017_03 PARTITION OF payment
767
+ FOR VALUES FROM ('2017-03-01 00:00:00+3:00') TO ('2017-04-01 00:00:00+3:00');
768
+
769
+
770
+ ALTER TABLE payment_p2017_03 OWNER TO postgres;
771
+
772
+ --
773
+ -- Name: payment_p2017_04; Type: TABLE; Schema: public; Owner: postgres
774
+ --
775
+
776
+ CREATE TABLE payment_p2017_04 PARTITION OF payment
777
+ FOR VALUES FROM ('2017-04-01 00:00:00+3:00') TO ('2017-05-01 00:00:00+3:00');
778
+
779
+ ALTER TABLE payment_p2017_04 OWNER TO postgres;
780
+
781
+ --
782
+ -- Name: payment_p2017_05; Type: TABLE; Schema: public; Owner: postgres
783
+ --
784
+
785
+ CREATE TABLE payment_p2017_05 PARTITION OF payment
786
+ FOR VALUES FROM ('2017-05-01 00:00:00+3:00') TO ('2017-06-01 00:00:00+3:00');
787
+
788
+ ALTER TABLE payment_p2017_05 OWNER TO postgres;
789
+
790
+ --
791
+ -- Name: payment_p2017_06; Type: TABLE; Schema: public; Owner: postgres
792
+ --
793
+
794
+ CREATE TABLE payment_p2017_06 PARTITION OF payment
795
+ FOR VALUES FROM ('2017-06-01 00:00:00+3:00') TO ('2017-07-01 00:00:00+3:00');
796
+
797
+
798
+ ALTER TABLE payment_p2017_06 OWNER TO postgres;
799
+
800
+ --
801
+ -- Name: rental_rental_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
802
+ --
803
+
804
+ CREATE SEQUENCE rental_rental_id_seq
805
+ START WITH 1
806
+ INCREMENT BY 1
807
+ NO MINVALUE
808
+ NO MAXVALUE
809
+ CACHE 1;
810
+
811
+
812
+ ALTER TABLE rental_rental_id_seq OWNER TO postgres;
813
+
814
+ --
815
+ -- Name: rental; Type: TABLE; Schema: public; Owner: postgres
816
+ --
817
+
818
+ CREATE TABLE rental (
819
+ rental_id integer DEFAULT nextval('rental_rental_id_seq'::regclass) NOT NULL,
820
+ rental_date timestamp with time zone NOT NULL,
821
+ inventory_id integer NOT NULL,
822
+ customer_id smallint NOT NULL,
823
+ return_date timestamp with time zone,
824
+ staff_id smallint NOT NULL,
825
+ last_update timestamp with time zone DEFAULT now() NOT NULL
826
+ );
827
+
828
+
829
+ ALTER TABLE rental OWNER TO postgres;
830
+
831
+ --
832
+ -- Name: sales_by_film_category; Type: VIEW; Schema: public; Owner: postgres
833
+ --
834
+
835
+ CREATE VIEW sales_by_film_category AS
836
+ SELECT c.name AS category,
837
+ sum(p.amount) AS total_sales
838
+ FROM (((((payment p
839
+ JOIN rental r ON ((p.rental_id = r.rental_id)))
840
+ JOIN inventory i ON ((r.inventory_id = i.inventory_id)))
841
+ JOIN film f ON ((i.film_id = f.film_id)))
842
+ JOIN film_category fc ON ((f.film_id = fc.film_id)))
843
+ JOIN category c ON ((fc.category_id = c.category_id)))
844
+ GROUP BY c.name
845
+ ORDER BY (sum(p.amount)) DESC;
846
+
847
+
848
+ ALTER TABLE sales_by_film_category OWNER TO postgres;
849
+
850
+ --
851
+ -- Name: staff_staff_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
852
+ --
853
+
854
+ CREATE SEQUENCE staff_staff_id_seq
855
+ START WITH 1
856
+ INCREMENT BY 1
857
+ NO MINVALUE
858
+ NO MAXVALUE
859
+ CACHE 1;
860
+
861
+
862
+ ALTER TABLE staff_staff_id_seq OWNER TO postgres;
863
+
864
+ --
865
+ -- Name: staff; Type: TABLE; Schema: public; Owner: postgres
866
+ --
867
+
868
+ CREATE TABLE staff (
869
+ staff_id integer DEFAULT nextval('staff_staff_id_seq'::regclass) NOT NULL,
870
+ first_name text NOT NULL,
871
+ last_name text NOT NULL,
872
+ address_id smallint NOT NULL,
873
+ email text,
874
+ store_id smallint NOT NULL,
875
+ active boolean DEFAULT true NOT NULL,
876
+ username text NOT NULL,
877
+ password text,
878
+ last_update timestamp with time zone DEFAULT now() NOT NULL,
879
+ picture bytea
880
+ );
881
+
882
+
883
+ ALTER TABLE staff OWNER TO postgres;
884
+
885
+ --
886
+ -- Name: store_store_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
887
+ --
888
+
889
+ CREATE SEQUENCE store_store_id_seq
890
+ START WITH 1
891
+ INCREMENT BY 1
892
+ NO MINVALUE
893
+ NO MAXVALUE
894
+ CACHE 1;
895
+
896
+
897
+ ALTER TABLE store_store_id_seq OWNER TO postgres;
898
+
899
+ --
900
+ -- Name: store; Type: TABLE; Schema: public; Owner: postgres
901
+ --
902
+
903
+ CREATE TABLE store (
904
+ store_id integer DEFAULT nextval('store_store_id_seq'::regclass) NOT NULL,
905
+ manager_staff_id smallint NOT NULL,
906
+ address_id smallint NOT NULL,
907
+ last_update timestamp with time zone DEFAULT now() NOT NULL
908
+ );
909
+
910
+
911
+ ALTER TABLE store OWNER TO postgres;
912
+
913
+ --
914
+ -- Name: sales_by_store; Type: VIEW; Schema: public; Owner: postgres
915
+ --
916
+
917
+ CREATE VIEW sales_by_store AS
918
+ SELECT (((c.city)::text || ','::text) || (cy.country)::text) AS store,
919
+ (((m.first_name)::text || ' '::text) || (m.last_name)::text) AS manager,
920
+ sum(p.amount) AS total_sales
921
+ FROM (((((((payment p
922
+ JOIN rental r ON ((p.rental_id = r.rental_id)))
923
+ JOIN inventory i ON ((r.inventory_id = i.inventory_id)))
924
+ JOIN store s ON ((i.store_id = s.store_id)))
925
+ JOIN address a ON ((s.address_id = a.address_id)))
926
+ JOIN city c ON ((a.city_id = c.city_id)))
927
+ JOIN country cy ON ((c.country_id = cy.country_id)))
928
+ JOIN staff m ON ((s.manager_staff_id = m.staff_id)))
929
+ GROUP BY cy.country, c.city, s.store_id, m.first_name, m.last_name
930
+ ORDER BY cy.country, c.city;
931
+
932
+
933
+ ALTER TABLE sales_by_store OWNER TO postgres;
934
+
935
+ --
936
+ -- Name: staff_list; Type: VIEW; Schema: public; Owner: postgres
937
+ --
938
+
939
+ CREATE VIEW staff_list AS
940
+ SELECT s.staff_id AS id,
941
+ (((s.first_name)::text || ' '::text) || (s.last_name)::text) AS name,
942
+ a.address,
943
+ a.postal_code AS "zip code",
944
+ a.phone,
945
+ city.city,
946
+ country.country,
947
+ s.store_id AS sid
948
+ FROM (((staff s
949
+ JOIN address a ON ((s.address_id = a.address_id)))
950
+ JOIN city ON ((a.city_id = city.city_id)))
951
+ JOIN country ON ((city.country_id = country.country_id)));
952
+
953
+
954
+ ALTER TABLE staff_list OWNER TO postgres;
955
+
956
+ --
957
+ -- Name: actor actor_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
958
+ --
959
+
960
+ ALTER TABLE ONLY actor
961
+ ADD CONSTRAINT actor_pkey PRIMARY KEY (actor_id);
962
+
963
+
964
+ --
965
+ -- Name: address address_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
966
+ --
967
+
968
+ ALTER TABLE ONLY address
969
+ ADD CONSTRAINT address_pkey PRIMARY KEY (address_id);
970
+
971
+
972
+ --
973
+ -- Name: category category_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
974
+ --
975
+
976
+ ALTER TABLE ONLY category
977
+ ADD CONSTRAINT category_pkey PRIMARY KEY (category_id);
978
+
979
+
980
+ --
981
+ -- Name: city city_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
982
+ --
983
+
984
+ ALTER TABLE ONLY city
985
+ ADD CONSTRAINT city_pkey PRIMARY KEY (city_id);
986
+
987
+
988
+ --
989
+ -- Name: country country_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
990
+ --
991
+
992
+ ALTER TABLE ONLY country
993
+ ADD CONSTRAINT country_pkey PRIMARY KEY (country_id);
994
+
995
+
996
+
997
+ --
998
+ -- Name: film_actor film_actor_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
999
+ --
1000
+
1001
+ ALTER TABLE ONLY film_actor
1002
+ ADD CONSTRAINT film_actor_pkey PRIMARY KEY (actor_id, film_id);
1003
+
1004
+
1005
+ --
1006
+ -- Name: film_category film_category_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1007
+ --
1008
+
1009
+ ALTER TABLE ONLY film_category
1010
+ ADD CONSTRAINT film_category_pkey PRIMARY KEY (film_id, category_id);
1011
+
1012
+
1013
+ --
1014
+ -- Name: film film_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1015
+ --
1016
+
1017
+ ALTER TABLE ONLY film
1018
+ ADD CONSTRAINT film_pkey PRIMARY KEY (film_id);
1019
+
1020
+
1021
+ --
1022
+ -- Name: inventory inventory_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1023
+ --
1024
+
1025
+ ALTER TABLE ONLY inventory
1026
+ ADD CONSTRAINT inventory_pkey PRIMARY KEY (inventory_id);
1027
+
1028
+
1029
+ --
1030
+ -- Name: language language_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1031
+ --
1032
+
1033
+ ALTER TABLE ONLY language
1034
+ ADD CONSTRAINT language_pkey PRIMARY KEY (language_id);
1035
+
1036
+
1037
+ --
1038
+ -- Name: rental rental_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1039
+ --
1040
+
1041
+ ALTER TABLE ONLY rental
1042
+ ADD CONSTRAINT rental_pkey PRIMARY KEY (rental_id);
1043
+
1044
+
1045
+ --
1046
+ -- Name: staff staff_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1047
+ --
1048
+
1049
+ ALTER TABLE ONLY staff
1050
+ ADD CONSTRAINT staff_pkey PRIMARY KEY (staff_id);
1051
+
1052
+
1053
+ --
1054
+ -- Name: store store_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1055
+ --
1056
+
1057
+ ALTER TABLE ONLY store
1058
+ ADD CONSTRAINT store_pkey PRIMARY KEY (store_id);
1059
+
1060
+
1061
+ --
1062
+ -- Name: film_fulltext_idx; Type: INDEX; Schema: public; Owner: postgres
1063
+ --
1064
+
1065
+ CREATE INDEX film_fulltext_idx ON film USING gist (fulltext);
1066
+
1067
+
1068
+ --
1069
+ -- Name: idx_actor_last_name; Type: INDEX; Schema: public; Owner: postgres
1070
+ --
1071
+
1072
+ CREATE INDEX idx_actor_last_name ON actor USING btree (last_name);
1073
+
1074
+
1075
+ --
1076
+ -- Name: idx_fk_address_id; Type: INDEX; Schema: public; Owner: postgres
1077
+ --
1078
+
1079
+ CREATE INDEX idx_fk_address_id ON customer USING btree (address_id);
1080
+
1081
+
1082
+ --
1083
+ -- Name: idx_fk_city_id; Type: INDEX; Schema: public; Owner: postgres
1084
+ --
1085
+
1086
+ CREATE INDEX idx_fk_city_id ON address USING btree (city_id);
1087
+
1088
+
1089
+ --
1090
+ -- Name: idx_fk_country_id; Type: INDEX; Schema: public; Owner: postgres
1091
+ --
1092
+
1093
+ CREATE INDEX idx_fk_country_id ON city USING btree (country_id);
1094
+
1095
+
1096
+ --
1097
+ -- Name: idx_fk_customer_id; Type: INDEX; Schema: public; Owner: postgres
1098
+ --
1099
+
1100
+ CREATE INDEX idx_fk_customer_id ON payment USING btree (customer_id);
1101
+
1102
+
1103
+ --
1104
+ -- Name: idx_fk_film_id; Type: INDEX; Schema: public; Owner: postgres
1105
+ --
1106
+
1107
+ CREATE INDEX idx_fk_film_id ON film_actor USING btree (film_id);
1108
+
1109
+
1110
+ --
1111
+ -- Name: idx_fk_inventory_id; Type: INDEX; Schema: public; Owner: postgres
1112
+ --
1113
+
1114
+ CREATE INDEX idx_fk_inventory_id ON rental USING btree (inventory_id);
1115
+
1116
+
1117
+ --
1118
+ -- Name: idx_fk_language_id; Type: INDEX; Schema: public; Owner: postgres
1119
+ --
1120
+
1121
+ CREATE INDEX idx_fk_language_id ON film USING btree (language_id);
1122
+
1123
+
1124
+ --
1125
+ -- Name: idx_fk_original_language_id; Type: INDEX; Schema: public; Owner: postgres
1126
+ --
1127
+
1128
+ CREATE INDEX idx_fk_original_language_id ON film USING btree (original_language_id);
1129
+
1130
+
1131
+ --
1132
+ -- Name: idx_fk_payment_p2017_01_customer_id; Type: INDEX; Schema: public; Owner: postgres
1133
+ --
1134
+
1135
+ CREATE INDEX idx_fk_payment_p2017_01_customer_id ON payment_p2017_01 USING btree (customer_id);
1136
+
1137
+
1138
+ --
1139
+ -- Name: idx_fk_payment_p2017_01_staff_id; Type: INDEX; Schema: public; Owner: postgres
1140
+ --
1141
+
1142
+ CREATE INDEX idx_fk_payment_p2017_01_staff_id ON payment_p2017_01 USING btree (staff_id);
1143
+
1144
+
1145
+ --
1146
+ -- Name: idx_fk_payment_p2017_02_customer_id; Type: INDEX; Schema: public; Owner: postgres
1147
+ --
1148
+
1149
+ CREATE INDEX idx_fk_payment_p2017_02_customer_id ON payment_p2017_02 USING btree (customer_id);
1150
+
1151
+
1152
+ --
1153
+ -- Name: idx_fk_payment_p2017_02_staff_id; Type: INDEX; Schema: public; Owner: postgres
1154
+ --
1155
+
1156
+ CREATE INDEX idx_fk_payment_p2017_02_staff_id ON payment_p2017_02 USING btree (staff_id);
1157
+
1158
+
1159
+ --
1160
+ -- Name: idx_fk_payment_p2017_03_customer_id; Type: INDEX; Schema: public; Owner: postgres
1161
+ --
1162
+
1163
+ CREATE INDEX idx_fk_payment_p2017_03_customer_id ON payment_p2017_03 USING btree (customer_id);
1164
+
1165
+
1166
+ --
1167
+ -- Name: idx_fk_payment_p2017_03_staff_id; Type: INDEX; Schema: public; Owner: postgres
1168
+ --
1169
+
1170
+ CREATE INDEX idx_fk_payment_p2017_03_staff_id ON payment_p2017_03 USING btree (staff_id);
1171
+
1172
+
1173
+ --
1174
+ -- Name: idx_fk_payment_p2017_04_customer_id; Type: INDEX; Schema: public; Owner: postgres
1175
+ --
1176
+
1177
+ CREATE INDEX idx_fk_payment_p2017_04_customer_id ON payment_p2017_04 USING btree (customer_id);
1178
+
1179
+
1180
+ --
1181
+ -- Name: idx_fk_payment_p2017_04_staff_id; Type: INDEX; Schema: public; Owner: postgres
1182
+ --
1183
+
1184
+ CREATE INDEX idx_fk_payment_p2017_04_staff_id ON payment_p2017_04 USING btree (staff_id);
1185
+
1186
+
1187
+ --
1188
+ -- Name: idx_fk_payment_p2017_05_customer_id; Type: INDEX; Schema: public; Owner: postgres
1189
+ --
1190
+
1191
+ CREATE INDEX idx_fk_payment_p2017_05_customer_id ON payment_p2017_05 USING btree (customer_id);
1192
+
1193
+
1194
+ --
1195
+ -- Name: idx_fk_payment_p2017_05_staff_id; Type: INDEX; Schema: public; Owner: postgres
1196
+ --
1197
+
1198
+ CREATE INDEX idx_fk_payment_p2017_05_staff_id ON payment_p2017_05 USING btree (staff_id);
1199
+
1200
+
1201
+ --
1202
+ -- Name: idx_fk_payment_p2017_06_customer_id; Type: INDEX; Schema: public; Owner: postgres
1203
+ --
1204
+
1205
+ CREATE INDEX idx_fk_payment_p2017_06_customer_id ON payment_p2017_06 USING btree (customer_id);
1206
+
1207
+
1208
+ --
1209
+ -- Name: idx_fk_payment_p2017_06_staff_id; Type: INDEX; Schema: public; Owner: postgres
1210
+ --
1211
+
1212
+ CREATE INDEX idx_fk_payment_p2017_06_staff_id ON payment_p2017_06 USING btree (staff_id);
1213
+
1214
+
1215
+ --
1216
+ -- Name: idx_fk_staff_id; Type: INDEX; Schema: public; Owner: postgres
1217
+ --
1218
+
1219
+ CREATE INDEX idx_fk_staff_id ON payment USING btree (staff_id);
1220
+
1221
+
1222
+ --
1223
+ -- Name: idx_fk_store_id; Type: INDEX; Schema: public; Owner: postgres
1224
+ --
1225
+
1226
+ CREATE INDEX idx_fk_store_id ON customer USING btree (store_id);
1227
+
1228
+
1229
+ --
1230
+ -- Name: idx_last_name; Type: INDEX; Schema: public; Owner: postgres
1231
+ --
1232
+
1233
+ CREATE INDEX idx_last_name ON customer USING btree (last_name);
1234
+
1235
+
1236
+ --
1237
+ -- Name: idx_store_id_film_id; Type: INDEX; Schema: public; Owner: postgres
1238
+ --
1239
+
1240
+ CREATE INDEX idx_store_id_film_id ON inventory USING btree (store_id, film_id);
1241
+
1242
+
1243
+ --
1244
+ -- Name: idx_title; Type: INDEX; Schema: public; Owner: postgres
1245
+ --
1246
+
1247
+ CREATE INDEX idx_title ON film USING btree (title);
1248
+
1249
+
1250
+ --
1251
+ -- Name: idx_unq_manager_staff_id; Type: INDEX; Schema: public; Owner: postgres
1252
+ --
1253
+
1254
+ CREATE UNIQUE INDEX idx_unq_manager_staff_id ON store USING btree (manager_staff_id);
1255
+
1256
+
1257
+ --
1258
+ -- Name: idx_unq_rental_rental_date_inventory_id_customer_id; Type: INDEX; Schema: public; Owner: postgres
1259
+ --
1260
+
1261
+ CREATE UNIQUE INDEX idx_unq_rental_rental_date_inventory_id_customer_id ON rental USING btree (rental_date, inventory_id, customer_id);
1262
+
1263
+ --
1264
+ -- Name: film film_fulltext_trigger; Type: TRIGGER; Schema: public; Owner: postgres
1265
+ --
1266
+
1267
+ CREATE TRIGGER film_fulltext_trigger BEFORE INSERT OR UPDATE ON film FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('fulltext', 'pg_catalog.english', 'title', 'description');
1268
+
1269
+
1270
+ --
1271
+ -- Name: actor last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1272
+ --
1273
+
1274
+ CREATE TRIGGER last_updated BEFORE UPDATE ON actor FOR EACH ROW EXECUTE PROCEDURE last_updated();
1275
+
1276
+
1277
+ --
1278
+ -- Name: address last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1279
+ --
1280
+
1281
+ CREATE TRIGGER last_updated BEFORE UPDATE ON address FOR EACH ROW EXECUTE PROCEDURE last_updated();
1282
+
1283
+
1284
+ --
1285
+ -- Name: category last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1286
+ --
1287
+
1288
+ CREATE TRIGGER last_updated BEFORE UPDATE ON category FOR EACH ROW EXECUTE PROCEDURE last_updated();
1289
+
1290
+
1291
+ --
1292
+ -- Name: city last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1293
+ --
1294
+
1295
+ CREATE TRIGGER last_updated BEFORE UPDATE ON city FOR EACH ROW EXECUTE PROCEDURE last_updated();
1296
+
1297
+
1298
+ --
1299
+ -- Name: country last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1300
+ --
1301
+
1302
+ CREATE TRIGGER last_updated BEFORE UPDATE ON country FOR EACH ROW EXECUTE PROCEDURE last_updated();
1303
+
1304
+
1305
+ --
1306
+ -- Name: customer last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1307
+ --
1308
+
1309
+ CREATE TRIGGER last_updated BEFORE UPDATE ON customer FOR EACH ROW EXECUTE PROCEDURE last_updated();
1310
+
1311
+
1312
+ --
1313
+ -- Name: film last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1314
+ --
1315
+
1316
+ CREATE TRIGGER last_updated BEFORE UPDATE ON film FOR EACH ROW EXECUTE PROCEDURE last_updated();
1317
+
1318
+
1319
+ --
1320
+ -- Name: film_actor last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1321
+ --
1322
+
1323
+ CREATE TRIGGER last_updated BEFORE UPDATE ON film_actor FOR EACH ROW EXECUTE PROCEDURE last_updated();
1324
+
1325
+
1326
+ --
1327
+ -- Name: film_category last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1328
+ --
1329
+
1330
+ CREATE TRIGGER last_updated BEFORE UPDATE ON film_category FOR EACH ROW EXECUTE PROCEDURE last_updated();
1331
+
1332
+
1333
+ --
1334
+ -- Name: inventory last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1335
+ --
1336
+
1337
+ CREATE TRIGGER last_updated BEFORE UPDATE ON inventory FOR EACH ROW EXECUTE PROCEDURE last_updated();
1338
+
1339
+
1340
+ --
1341
+ -- Name: language last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1342
+ --
1343
+
1344
+ CREATE TRIGGER last_updated BEFORE UPDATE ON language FOR EACH ROW EXECUTE PROCEDURE last_updated();
1345
+
1346
+
1347
+ --
1348
+ -- Name: rental last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1349
+ --
1350
+
1351
+ CREATE TRIGGER last_updated BEFORE UPDATE ON rental FOR EACH ROW EXECUTE PROCEDURE last_updated();
1352
+
1353
+
1354
+ --
1355
+ -- Name: staff last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1356
+ --
1357
+
1358
+ CREATE TRIGGER last_updated BEFORE UPDATE ON staff FOR EACH ROW EXECUTE PROCEDURE last_updated();
1359
+
1360
+
1361
+ --
1362
+ -- Name: store last_updated; Type: TRIGGER; Schema: public; Owner: postgres
1363
+ --
1364
+
1365
+ CREATE TRIGGER last_updated BEFORE UPDATE ON store FOR EACH ROW EXECUTE PROCEDURE last_updated();
1366
+
1367
+
1368
+ --
1369
+ -- Name: address address_city_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1370
+ --
1371
+
1372
+ ALTER TABLE ONLY address
1373
+ ADD CONSTRAINT address_city_id_fkey FOREIGN KEY (city_id) REFERENCES city(city_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1374
+
1375
+
1376
+ --
1377
+ -- Name: city city_country_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1378
+ --
1379
+
1380
+ ALTER TABLE ONLY city
1381
+ ADD CONSTRAINT city_country_id_fkey FOREIGN KEY (country_id) REFERENCES country(country_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1382
+
1383
+
1384
+ --
1385
+ -- Name: customer customer_address_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1386
+ --
1387
+
1388
+ ALTER TABLE ONLY customer
1389
+ ADD CONSTRAINT customer_address_id_fkey FOREIGN KEY (address_id) REFERENCES address(address_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1390
+
1391
+
1392
+ --
1393
+ -- Name: customer customer_store_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1394
+ --
1395
+
1396
+ ALTER TABLE ONLY customer
1397
+ ADD CONSTRAINT customer_store_id_fkey FOREIGN KEY (store_id) REFERENCES store(store_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1398
+
1399
+
1400
+ --
1401
+ -- Name: film_actor film_actor_actor_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1402
+ --
1403
+
1404
+ ALTER TABLE ONLY film_actor
1405
+ ADD CONSTRAINT film_actor_actor_id_fkey FOREIGN KEY (actor_id) REFERENCES actor(actor_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1406
+
1407
+
1408
+ --
1409
+ -- Name: film_actor film_actor_film_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1410
+ --
1411
+
1412
+ ALTER TABLE ONLY film_actor
1413
+ ADD CONSTRAINT film_actor_film_id_fkey FOREIGN KEY (film_id) REFERENCES film(film_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1414
+
1415
+
1416
+ --
1417
+ -- Name: film_category film_category_category_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1418
+ --
1419
+
1420
+ ALTER TABLE ONLY film_category
1421
+ ADD CONSTRAINT film_category_category_id_fkey FOREIGN KEY (category_id) REFERENCES category(category_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1422
+
1423
+
1424
+ --
1425
+ -- Name: film_category film_category_film_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1426
+ --
1427
+
1428
+ ALTER TABLE ONLY film_category
1429
+ ADD CONSTRAINT film_category_film_id_fkey FOREIGN KEY (film_id) REFERENCES film(film_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1430
+
1431
+
1432
+ --
1433
+ -- Name: film film_language_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1434
+ --
1435
+
1436
+ ALTER TABLE ONLY film
1437
+ ADD CONSTRAINT film_language_id_fkey FOREIGN KEY (language_id) REFERENCES language(language_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1438
+
1439
+
1440
+ --
1441
+ -- Name: film film_original_language_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1442
+ --
1443
+
1444
+ ALTER TABLE ONLY film
1445
+ ADD CONSTRAINT film_original_language_id_fkey FOREIGN KEY (original_language_id) REFERENCES language(language_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1446
+
1447
+
1448
+ --
1449
+ -- Name: inventory inventory_film_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1450
+ --
1451
+
1452
+ ALTER TABLE ONLY inventory
1453
+ ADD CONSTRAINT inventory_film_id_fkey FOREIGN KEY (film_id) REFERENCES film(film_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1454
+
1455
+
1456
+ --
1457
+ -- Name: inventory inventory_store_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1458
+ --
1459
+
1460
+ ALTER TABLE ONLY inventory
1461
+ ADD CONSTRAINT inventory_store_id_fkey FOREIGN KEY (store_id) REFERENCES store(store_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1462
+
1463
+ --
1464
+ -- Name: rental rental_customer_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1465
+ --
1466
+
1467
+ ALTER TABLE ONLY rental
1468
+ ADD CONSTRAINT rental_customer_id_fkey FOREIGN KEY (customer_id) REFERENCES customer(customer_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1469
+
1470
+
1471
+ --
1472
+ -- Name: rental rental_inventory_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1473
+ --
1474
+
1475
+ ALTER TABLE ONLY rental
1476
+ ADD CONSTRAINT rental_inventory_id_fkey FOREIGN KEY (inventory_id) REFERENCES inventory(inventory_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1477
+
1478
+
1479
+ --
1480
+ -- Name: rental rental_staff_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1481
+ --
1482
+
1483
+ ALTER TABLE ONLY rental
1484
+ ADD CONSTRAINT rental_staff_id_fkey FOREIGN KEY (staff_id) REFERENCES staff(staff_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1485
+
1486
+
1487
+ --
1488
+ -- Name: staff staff_address_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1489
+ --
1490
+
1491
+ ALTER TABLE ONLY staff
1492
+ ADD CONSTRAINT staff_address_id_fkey FOREIGN KEY (address_id) REFERENCES address(address_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1493
+
1494
+
1495
+ --
1496
+ -- Name: staff staff_store_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1497
+ --
1498
+
1499
+ ALTER TABLE ONLY staff
1500
+ ADD CONSTRAINT staff_store_id_fkey FOREIGN KEY (store_id) REFERENCES store(store_id);
1501
+
1502
+
1503
+ --
1504
+ -- Name: store store_address_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
1505
+ --
1506
+
1507
+ ALTER TABLE ONLY store
1508
+ ADD CONSTRAINT store_address_id_fkey FOREIGN KEY (address_id) REFERENCES address(address_id) ON UPDATE CASCADE ON DELETE RESTRICT;
1509
+
1510
+
1511
+ --
1512
+ -- PostgreSQL database dump complete
1513
+ --
1514
+
1515
+
1516
+ ALTER TABLE payment_p2017_01
1517
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1518
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1519
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
1520
+
1521
+ ALTER TABLE payment_p2017_02
1522
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1523
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1524
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
1525
+
1526
+ ALTER TABLE payment_p2017_03
1527
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1528
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1529
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
1530
+
1531
+ ALTER TABLE payment_p2017_04
1532
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1533
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1534
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
1535
+
1536
+ ALTER TABLE payment_p2017_05
1537
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1538
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1539
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
1540
+
1541
+ ALTER TABLE payment_p2017_06
1542
+ ADD FOREIGN KEY(customer_id) REFERENCES customer(customer_id),
1543
+ ADD FOREIGN KEY(staff_id) REFERENCES staff(staff_id),
1544
+ ADD FOREIGN KEY(rental_id) REFERENCES rental(rental_id);
pagila/2. pagila-insert-data.sql ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ streamlit
4
+ pandas
5
+ python-dotenv
6
+ google-generativeai
7
+ requests
8
+ psycopg2-binary
streamlit_app.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # streamlit_app.py
2
+ import streamlit as st
3
+ import requests
4
+ import pandas as pd
5
+
6
+ st.set_page_config(page_title="QueryMate: Natural Language to SQL")
7
+
8
+ st.markdown("# Text to SQL - PagilaDB🤖")
9
+ st.markdown('''Your friendly assistant for converting natural language queries into SQL statements!
10
+ Ask questions about the Pagila DVD rental database.''')
11
+
12
+ # Initialize chat history
13
+ if 'chat_history' not in st.session_state:
14
+ st.session_state.chat_history = []
15
+
16
+ # Predefined queries
17
+ # Update the predefined_queries list
18
+ predefined_queries = [
19
+ 'List the top 10 most rented movies with their rental counts',
20
+ 'Calculate total revenue for each movie category',
21
+ 'Find customers who have spent more than $150 total',
22
+ 'Show all movies in the Action category with their rental rates',
23
+ ]
24
+
25
+ st.markdown("### Predefined Queries")
26
+ for query in predefined_queries:
27
+ if st.button(query):
28
+ st.session_state.predefined_query = query
29
+
30
+ st.markdown("### Enter Your Question")
31
+ question = st.text_input("Input: ", key="input", value=st.session_state.get('predefined_query', ''))
32
+
33
+ if st.button("Submit"):
34
+ response = requests.post("http://localhost:8000/query",
35
+ json={"question": question})
36
+ if response.status_code == 200:
37
+ data = response.json()
38
+ st.markdown("## Generated SQL Query")
39
+ st.code(data['query'], language='sql')
40
+
41
+ st.markdown("## Query Results")
42
+ df = pd.DataFrame(data['result'])
43
+ st.dataframe(df)
44
+
45
+ # Update chat history
46
+ st.session_state.chat_history.append(f"👨‍💻: {question}")
47
+ st.session_state.chat_history.append(f"🤖: {data['query']}")
48
+ else:
49
+ st.error(f"Error: {response.text}")
50
+
51
+ st.session_state.pop('predefined_query', None)
52
+
53
+ st.markdown("## Chat History")
54
+ for message in st.session_state.chat_history:
55
+ st.text(message)
56
+
57
+ if st.button("Clear History"):
58
+ st.session_state.chat_history = []
59
+ st.success("Chat history cleared!")
tests/Pagila Evals Dataset(Sheet1).csv ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Query Number,Natural Language Query,Difficulty
2
+ 1,List all actors' first and last names.,Easy
3
+ 2,Show the titles of all films in the database.,Easy
4
+ 3,Get the names of all cities.,Easy
5
+ 4,List all categories available for films.,Easy
6
+ 5,Show the first name and last name of all customers.,Easy
7
+ 6,Show all films released in 2006.,Easy
8
+ 7,"Find all actors with the last name ""Smith.""",Easy
9
+ 8,List all customers who are from the city of �New York.�,Easy
10
+ 9,Get all stores located in the country �India.�,Easy
11
+ 10,Show all films with a rental rate greater than $2.99.,Easy
12
+ 11,How many films are there in each category?,Medium
13
+ 12,What is the total number of actors?,Medium
14
+ 13,Get the total payment received in June 2022.,Medium
15
+ 14,Find the total number of rentals made last month.,Medium
16
+ 15,How many films have a rating of �PG-13�?,Medium
17
+ 16,List all films along with their category names.,Medium
18
+ 17,"Show all actors who appeared in the film ""Inception.""",Medium
19
+ 18,Get a list of all customers and the films they have rented.,Medium
20
+ 19,List all staff members along with the stores they work at.,Medium
21
+ 20,"Find all films rented by customer ""John Doe.""",Medium
22
+ 21,Show the top 5 films rented the most across all stores.,Medium
23
+ 22,List all customers who have rented films in both store 1 and store 2.,Medium
24
+ 23,Find all actors who have appeared in more than 10 films.,Medium
25
+ 24,Get a list of customers who have made more than 5 payments.,Medium
26
+ 25,"List all films that are in both the ""Action"" and ""Comedy"" categories.",Medium
27
+ 26,Show all rentals made in the last 7 days.,Medium
28
+ 27,Get all payments made in February 2022.,Medium
29
+ 28,List all films that have not been rented in the last 30 days.,Medium
30
+ 29,Find all customers who registered in the last 6 months.,Medium
31
+ 30,"Show all staff members hired before January 1, 2020.",Medium
32
+ 31,List the top 3 customers who have spent the most in each country.,Hard
33
+ 32,Find the films that have been rented more times than the average number of rentals per film.,Hard
34
+ 33,"For each actor, show their name and the percentage of films they've acted in compared to the total films.",Hard
35
+ 34,Show the average payment amount for each customer.,Hard
36
+ 35,List all actors who have appeared in at least one film in each category.,Hard
37
+ 36,Find customers who have rented more films this year than last year.,Hard
38
+ 37,List the top 5 films with the highest revenue.,Hard
39
+ 38,"For each customer, show the number of films rented in the last month compared to the previous month.",Hard
40
+ 39,Show the names of customers who have rented every film in the �Action� category.,Hard
41
+ 40,List customers who have rented the same film more than 3 times.,Hard
tests/results/query_results.json ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "natural_language_query": "List all actors' first and last names.",
4
+ "sql_query": "SELECT first_name, last_name FROM actor;",
5
+ "difficulty": "Easy",
6
+ "is_valid": true,
7
+ "error": null
8
+ },
9
+ "2": {
10
+ "natural_language_query": "Show the titles of all films in the database.",
11
+ "sql_query": "SELECT title FROM film;",
12
+ "difficulty": "Easy",
13
+ "is_valid": true,
14
+ "error": null
15
+ },
16
+ "3": {
17
+ "natural_language_query": "Get the names of all cities.",
18
+ "sql_query": "SELECT city FROM city;",
19
+ "difficulty": "Easy",
20
+ "is_valid": true,
21
+ "error": null
22
+ },
23
+ "4": {
24
+ "natural_language_query": "List all categories available for films.",
25
+ "sql_query": "SELECT name FROM category;",
26
+ "difficulty": "Easy",
27
+ "is_valid": true,
28
+ "error": null
29
+ },
30
+ "5": {
31
+ "natural_language_query": "Show the first name and last name of all customers.",
32
+ "sql_query": "SELECT first_name, last_name FROM customer;",
33
+ "difficulty": "Easy",
34
+ "is_valid": true,
35
+ "error": null
36
+ },
37
+ "6": {
38
+ "natural_language_query": "Show all films released in 2006.",
39
+ "sql_query": "SELECT * FROM film WHERE release_year = 2006;",
40
+ "difficulty": "Easy",
41
+ "is_valid": true,
42
+ "error": null
43
+ },
44
+ "7": {
45
+ "natural_language_query": "Find all actors with the last name \"Smith.\"",
46
+ "sql_query": "SELECT * FROM actor WHERE last_name = 'Smith';",
47
+ "difficulty": "Easy",
48
+ "is_valid": true,
49
+ "error": null
50
+ },
51
+ "8": {
52
+ "natural_language_query": "List all customers who are from the city of “New York.”",
53
+ "sql_query": null,
54
+ "difficulty": "Easy",
55
+ "is_valid": false,
56
+ "error": "API quota exceeded"
57
+ },
58
+ "9": {
59
+ "natural_language_query": "Get all stores located in the country “India.”",
60
+ "sql_query": "SELECT store.store_id, address.address, city.city, country.country FROM store JOIN address ON store.address_id = address.address_id JOIN city ON address.city_id = city.city_id JOIN country ON city.country_id = country.country_id WHERE country.country = 'India';",
61
+ "difficulty": "Easy",
62
+ "is_valid": true,
63
+ "error": null
64
+ },
65
+ "10": {
66
+ "natural_language_query": "Show all films with a rental rate greater than $2.99.",
67
+ "sql_query": "SELECT * FROM film WHERE rental_rate > 2.99;",
68
+ "difficulty": "Easy",
69
+ "is_valid": true,
70
+ "error": null
71
+ },
72
+ "11": {
73
+ "natural_language_query": "How many films are there in each category?",
74
+ "sql_query": "SELECT c.name, COUNT(fc.film_id) FROM category c JOIN film_category fc ON c.category_id = fc.category_id GROUP BY c.name;",
75
+ "difficulty": "Medium",
76
+ "is_valid": true,
77
+ "error": null
78
+ },
79
+ "12": {
80
+ "natural_language_query": "What is the total number of actors?",
81
+ "sql_query": null,
82
+ "difficulty": "Medium",
83
+ "is_valid": false,
84
+ "error": "API quota exceeded"
85
+ },
86
+ "13": {
87
+ "natural_language_query": "Get the total payment received in June 2022.",
88
+ "sql_query": "SELECT SUM(amount) FROM payment WHERE payment_date BETWEEN '2007-06-01' AND '2007-06-30';",
89
+ "difficulty": "Medium",
90
+ "is_valid": true,
91
+ "error": null
92
+ },
93
+ "14": {
94
+ "natural_language_query": "Find the total number of rentals made last month.",
95
+ "sql_query": "SELECT COUNT(*) FROM rental WHERE DATE_TRUNC('month', rental_date) = DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month');",
96
+ "difficulty": "Medium",
97
+ "is_valid": true,
98
+ "error": null
99
+ },
100
+ "15": {
101
+ "natural_language_query": "How many films have a rating of “PG-13”?",
102
+ "sql_query": null,
103
+ "difficulty": "Medium",
104
+ "is_valid": false,
105
+ "error": "API quota exceeded"
106
+ },
107
+ "16": {
108
+ "natural_language_query": "List all films along with their category names.",
109
+ "sql_query": "SELECT f.title, c.name FROM film f JOIN film_category fc ON f.film_id = fc.film_id JOIN category c ON fc.category_id = c.category_id;",
110
+ "difficulty": "Medium",
111
+ "is_valid": true,
112
+ "error": null
113
+ },
114
+ "17": {
115
+ "natural_language_query": "Show all actors who appeared in the film \"Inception.\"",
116
+ "sql_query": null,
117
+ "difficulty": "Medium",
118
+ "is_valid": false,
119
+ "error": "API quota exceeded"
120
+ },
121
+ "18": {
122
+ "natural_language_query": "Get a list of all customers and the films they have rented.",
123
+ "sql_query": null,
124
+ "difficulty": "Medium",
125
+ "is_valid": false,
126
+ "error": "API quota exceeded"
127
+ },
128
+ "19": {
129
+ "natural_language_query": "List all staff members along with the stores they work at.",
130
+ "sql_query": null,
131
+ "difficulty": "Medium",
132
+ "is_valid": false,
133
+ "error": "API quota exceeded"
134
+ },
135
+ "20": {
136
+ "natural_language_query": "Find all films rented by customer \"John Doe.\"",
137
+ "sql_query": null,
138
+ "difficulty": "Medium",
139
+ "is_valid": false,
140
+ "error": "API quota exceeded"
141
+ },
142
+ "21": {
143
+ "natural_language_query": "Show the top 5 films rented the most across all stores.",
144
+ "sql_query": null,
145
+ "difficulty": "Medium",
146
+ "is_valid": false,
147
+ "error": "API quota exceeded"
148
+ },
149
+ "22": {
150
+ "natural_language_query": "List all customers who have rented films in both store 1 and store 2.",
151
+ "sql_query": null,
152
+ "difficulty": "Medium",
153
+ "is_valid": false,
154
+ "error": "API quota exceeded"
155
+ },
156
+ "23": {
157
+ "natural_language_query": "Find all actors who have appeared in more than 10 films.",
158
+ "sql_query": null,
159
+ "difficulty": "Medium",
160
+ "is_valid": false,
161
+ "error": "API quota exceeded"
162
+ },
163
+ "24": {
164
+ "natural_language_query": "Get a list of customers who have made more than 5 payments.",
165
+ "sql_query": null,
166
+ "difficulty": "Medium",
167
+ "is_valid": false,
168
+ "error": "API quota exceeded"
169
+ },
170
+ "25": {
171
+ "natural_language_query": "List all films that are in both the \"Action\" and \"Comedy\" categories.",
172
+ "sql_query": null,
173
+ "difficulty": "Medium",
174
+ "is_valid": false,
175
+ "error": "API quota exceeded"
176
+ },
177
+ "26": {
178
+ "natural_language_query": "Show all rentals made in the last 7 days.",
179
+ "sql_query": null,
180
+ "difficulty": "Medium",
181
+ "is_valid": false,
182
+ "error": "API quota exceeded"
183
+ },
184
+ "27": {
185
+ "natural_language_query": "Get all payments made in February 2022.",
186
+ "sql_query": null,
187
+ "difficulty": "Medium",
188
+ "is_valid": false,
189
+ "error": "API quota exceeded"
190
+ },
191
+ "28": {
192
+ "natural_language_query": "List all films that have not been rented in the last 30 days.",
193
+ "sql_query": null,
194
+ "difficulty": "Medium",
195
+ "is_valid": false,
196
+ "error": "API quota exceeded"
197
+ },
198
+ "29": {
199
+ "natural_language_query": "Find all customers who registered in the last 6 months.",
200
+ "sql_query": null,
201
+ "difficulty": "Medium",
202
+ "is_valid": false,
203
+ "error": "API quota exceeded"
204
+ },
205
+ "30": {
206
+ "natural_language_query": "Show all staff members hired before January 1, 2020.",
207
+ "sql_query": null,
208
+ "difficulty": "Medium",
209
+ "is_valid": false,
210
+ "error": "API quota exceeded"
211
+ },
212
+ "31": {
213
+ "natural_language_query": "List the top 3 customers who have spent the most in each country.",
214
+ "sql_query": null,
215
+ "difficulty": "Hard",
216
+ "is_valid": false,
217
+ "error": "API quota exceeded"
218
+ },
219
+ "32": {
220
+ "natural_language_query": "Find the films that have been rented more times than the average number of rentals per film.",
221
+ "sql_query": null,
222
+ "difficulty": "Hard",
223
+ "is_valid": false,
224
+ "error": "API quota exceeded"
225
+ },
226
+ "33": {
227
+ "natural_language_query": "For each actor, show their name and the percentage of films they've acted in compared to the total films.",
228
+ "sql_query": null,
229
+ "difficulty": "Hard",
230
+ "is_valid": false,
231
+ "error": "API quota exceeded"
232
+ },
233
+ "34": {
234
+ "natural_language_query": "Show the average payment amount for each customer.",
235
+ "sql_query": null,
236
+ "difficulty": "Hard",
237
+ "is_valid": false,
238
+ "error": "API quota exceeded"
239
+ },
240
+ "35": {
241
+ "natural_language_query": "List all actors who have appeared in at least one film in each category.",
242
+ "sql_query": null,
243
+ "difficulty": "Hard",
244
+ "is_valid": false,
245
+ "error": "API quota exceeded"
246
+ },
247
+ "36": {
248
+ "natural_language_query": "Find customers who have rented more films this year than last year.",
249
+ "sql_query": null,
250
+ "difficulty": "Hard",
251
+ "is_valid": false,
252
+ "error": "API quota exceeded"
253
+ },
254
+ "37": {
255
+ "natural_language_query": "List the top 5 films with the highest revenue.",
256
+ "sql_query": null,
257
+ "difficulty": "Hard",
258
+ "is_valid": false,
259
+ "error": "API quota exceeded"
260
+ },
261
+ "38": {
262
+ "natural_language_query": "For each customer, show the number of films rented in the last month compared to the previous month.",
263
+ "sql_query": null,
264
+ "difficulty": "Hard",
265
+ "is_valid": false,
266
+ "error": "API quota exceeded"
267
+ },
268
+ "39": {
269
+ "natural_language_query": "Show the names of customers who have rented every film in the “Action” category.",
270
+ "sql_query": null,
271
+ "difficulty": "Hard",
272
+ "is_valid": false,
273
+ "error": "API quota exceeded"
274
+ },
275
+ "40": {
276
+ "natural_language_query": "List customers who have rented the same film more than 3 times.",
277
+ "sql_query": null,
278
+ "difficulty": "Hard",
279
+ "is_valid": false,
280
+ "error": "API quota exceeded"
281
+ }
282
+ }
tests/test_queries.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import pandas as pd
4
+ import json
5
+ from pathlib import Path
6
+ import psycopg2
7
+ from dotenv import load_dotenv
8
+ import time
9
+ from tqdm import tqdm
10
+
11
+ sys.path.append(str(Path(__file__).parent.parent))
12
+ from main import get_gemini_response, sql_prompt
13
+
14
+ def validate_sql_query(query, conn):
15
+ """Validate if the SQL query is syntactically correct"""
16
+ try:
17
+ with conn.cursor() as cursor:
18
+ # Reset any aborted transaction
19
+ conn.rollback()
20
+
21
+ # Now try to validate the query
22
+ cursor.execute("EXPLAIN " + query)
23
+ conn.commit() # Commit the successful EXPLAIN
24
+ return True, None
25
+ except psycopg2.Error as e:
26
+ # Rollback on error
27
+ conn.rollback()
28
+ return False, str(e)
29
+
30
+ def handle_api_error(error):
31
+ """Handle different types of API errors"""
32
+ if "429" in str(error):
33
+ return "API quota exceeded", 30 # Wait 30 seconds
34
+ return str(error), 0
35
+
36
+ def run_query_tests():
37
+ load_dotenv()
38
+
39
+ # Database connection
40
+ conn = psycopg2.connect(
41
+ dbname=os.getenv('DB_NAME'),
42
+ user=os.getenv('DB_USER'),
43
+ password=os.getenv('DB_PASSWORD'),
44
+ host=os.getenv('DB_HOST'),
45
+ port=os.getenv('DB_PORT', '5432')
46
+ )
47
+
48
+ # Read the test dataset with encoding specification
49
+ csv_path = Path(__file__).parent / 'Pagila Evals Dataset(Sheet1).csv'
50
+ try:
51
+ test_data = pd.read_csv(csv_path, encoding='cp1252')
52
+ except UnicodeDecodeError:
53
+ # Fallback to latin-1 if cp1252 fails
54
+ test_data = pd.read_csv(csv_path, encoding='latin-1')
55
+
56
+ # Clean up any special quotes in the queries
57
+ test_data['Natural Language Query'] = test_data['Natural Language Query'].str.replace('"', '"').str.replace('"', '"')
58
+
59
+ results_dir = Path(__file__).parent / 'results'
60
+ results_dir.mkdir(exist_ok=True)
61
+
62
+ # Load existing results if any
63
+ output_file = results_dir / 'query_results.json'
64
+ if output_file.exists():
65
+ with open(output_file, 'r', encoding='utf-8') as f:
66
+ results = json.load(f)
67
+ else:
68
+ results = {}
69
+
70
+ # Process queries with progress bar
71
+ for _, row in tqdm(test_data.iterrows(), total=len(test_data), desc="Processing queries"):
72
+ query_num = str(row['Query Number'])
73
+
74
+ # Skip if already processed successfully
75
+ if query_num in results and results[query_num]['sql_query'] and results[query_num]['is_valid']:
76
+ continue
77
+
78
+ nl_query = row['Natural Language Query']
79
+ difficulty = row['Difficulty']
80
+
81
+ max_retries = 3
82
+ retry_count = 0
83
+
84
+ while retry_count < max_retries:
85
+ try:
86
+ sql_query = get_gemini_response(nl_query, sql_prompt)
87
+ sql_query = sql_query.replace('```sql', '').replace('```', '').strip()
88
+
89
+ is_valid, error_msg = validate_sql_query(sql_query, conn)
90
+
91
+ results[query_num] = {
92
+ 'natural_language_query': nl_query,
93
+ 'sql_query': sql_query,
94
+ 'difficulty': difficulty,
95
+ 'is_valid': is_valid,
96
+ 'error': error_msg
97
+ }
98
+
99
+ # Save progress after each successful query
100
+ with open(output_file, 'w', encoding='utf-8') as f:
101
+ json.dump(results, f, indent=2, ensure_ascii=False)
102
+
103
+ break # Success, exit retry loop
104
+
105
+ except Exception as e:
106
+ error_msg, wait_time = handle_api_error(e)
107
+ retry_count += 1
108
+
109
+ if wait_time > 0:
110
+ print(f"\nAPI quota exceeded. Waiting {wait_time} seconds...")
111
+ time.sleep(wait_time)
112
+
113
+ if retry_count == max_retries:
114
+ results[query_num] = {
115
+ 'natural_language_query': nl_query,
116
+ 'sql_query': None,
117
+ 'difficulty': difficulty,
118
+ 'is_valid': False,
119
+ 'error': error_msg
120
+ }
121
+
122
+ # Save progress even for failed queries
123
+ with open(output_file, 'w', encoding='utf-8') as f:
124
+ json.dump(results, f, indent=2, ensure_ascii=False)
125
+
126
+ conn.close()
127
+ print(f"\nResults saved to {output_file}")
128
+
129
+ if __name__ == "__main__":
130
+ run_query_tests()