Put information from a dabtabse file into lists - python-2.7

import sqlite3
db = sqlite3.connect('newdb.db')
team_list = ['Munster', 'Leinster', 'Ulster', 'Glasgow']
cursor = db.cursor()
for i in range(len(team_list)):
team_names = team_list[i].upper()
searchStr = '%' + team_names + '%'
cursor.execute('select * from tickets where Name LIKE ?', (searchStr,))
teams_points = cursor.fetchall()
print teams_points
cursor.close()
db.close()
This is my python code used to display all data in the table 'tickets' in newdb.db. I have a list with the team names and i want to be able to search these team names in the database and calculate information on tickets sold.
picture of database
[(u'MUNSTER', 5, u'First Round'), (u'MUNSTER', 5, u'First Round'),
(u'MUNSTER', 8, u'Second Round'), (u'MUNSTER', 10, u'Both Rounds')]
[(u'LEINSTER', 2, u'Second Round'), (u'LEINSTER', 16, u'First Round'),
(u'LEINSTER', 5, u'Both Rounds'), (u'LEINSTER', 6, u'Both Rounds'),
(u'LEINSTER', 3, u'First Round')]
[(u'ULSTER', 10, u'Second Round')]
[(u'GLASGOW', 4, u'First Round')]
Above is my output when I run the script, i want to be able put each team into a list as
team_list=['team_name', 'total first round tickets', 'second round tickets']
munster_list = ['MUNSTER', '20', '18']
leinster_list = ['LEINSTER','30','13']
ulster_list = ['ULSTER','0','10']
glasgow_list = ['GLASGOW','4','0']
so then to print the list I can just use print munster_list

Use GROUP BY to get one output row from the rows in each group. Use CASE expressions to sum up only certain values:
SELECT Name,
sum(CASE WHEN Type IN ('First Round', 'Both Rounds')
THEN Amount
ELSE 0
END) AS "first round tickets",
sum(CASE WHEN Type IN ('Second Round', 'Both Rounds')
THEN Amount
ELSE 0
END) AS "second round tickets"
FROM tickets
GROUP BY Name
ORDER BY Name;

Related

Get top n records for each group with Django queryset

I have a model like the following Table,
create table `mytable`
(
`person` varchar(10),
`groupname` int,
`age` int
);
And I want to get the 2 oldest people from each group. The original SQL question and answers are here StackOverflow and One of the solutions that work is
SELECT
person,
groupname,
age
FROM
(
SELECT
person,
groupname,
age,
#rn := IF(#prev = groupname, #rn + 1, 1) AS rn,
#prev := groupname
FROM mytable
JOIN (SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY groupname, age DESC, person
) AS T1
WHERE rn <= 2
You can check the SQL output here as well SQLFIDLE
I just want to know how can I implement this query in Django's views as queryset.
Another SQL with similar output would have window function that annotates each row with row number within particular group name and then you would filter row numbers lower or equal 2 in HAVING clause.
At the moment of writing django does not support filtering based on window function result so you need to calculate row in the first query and filter People in the second query.
Following code is based on similar question but it implements limiting number of rows to be returned per group_name.
from django.db.models import F, When, Window
from django.db.models.functions import RowNumber
person_ids = {
pk
for pk, row_no_in_group in Person.objects.annotate(
row_no_in_group=Window(
expression=RowNumber(),
partition_by=[F('group_name')],
order_by=['group_name', F('age').desc(), 'person']
)
).values_list('id', 'row_no_in_group')
if row_no_in_group <= 2
}
filtered_persons = Person.objects.filter(id__in=person_ids)
For following state of Person table
>>> Person.objects.order_by('group_name', '-age', 'person').values_list('group_name', 'age', 'person')
<QuerySet [(1, 19, 'Brian'), (1, 17, 'Brett'), (1, 14, 'Teresa'), (1, 13, 'Sydney'), (2, 20, 'Daniel'), (2, 18, 'Maureen'), (2, 14, 'Vincent'), (2, 12, 'Carlos'), (2, 11, 'Kathleen'), (2, 11, 'Sandra')]>
queries above return
>>> filtered_persons.order_by('group_name', '-age', 'person').values_list('group_name', 'age', 'person')
<QuerySet [(1, 19, 'Brian'), (1, 17, 'Brett'), (2, 20, 'Daniel'), (2, 18, 'Maureen')]>

Get Count of order on every day of week

Hi I have a model like :
class Order(models.Model):
user=models.ForeginKey(User)
startDatatime = models.DateTimeField(blank=True, null=True)
I want count orders on Each week day . like On all Mondays count of orders and on all week days etc
EDIT
Is that a good way to do that ?
data = []
weekdays = {'Sunday': 1, 'Monday': 2, 'Tuesday': 3, 'Wednesday': 4, ' Thursday': 5,
'Friday': 6, 'Saturday': 7}
for day, value in weekdays.items():
weekly_tasks_count = Task.objects.filter(
todo_list__for_user=request.user,
creation_date_time__week_day=value).count()
data.append({day: weekly_tasks_count})
You can use list comprehensions to tidy up your code a little bit more.
WEEKDAYS = {
'Sunday': 1,
'Monday': 2,
'Tuesday': 3,
'Wednesday': 4,
'Thursday': 5,
'Friday': 6,
'Saturday': 7
}
data = [
{
day: Task.objects.filter(
todo_list__for_user=request.user,
creation_date_time__week_day=value).count()
)}
for day, value in WEEKDAYS.items()
]
One more possible improvement is to build up the WEEKDAYS dictionary from values found in the datetime module, but so far having it defined your way doesn't harm readability.

summing up a column in a csv file based on user search

I have the following csv file:
data.cvs
school,students,teachers,subs
us-school1,10,2,0
us-school2,20,4,2
uk-school1,10,2,0
de-school1,10,3,1
de-school1,15,3,3
I am trying to have a user search for the school country (us or uk, or de)
and then sum up the corresponding column. (e.g. sum all students in us-* etc.)
So far i am able to search using the raw_input and display column contents corresponding to the country, appreciate if someone can give me some pointers on how i can achive this.
desired output:
Country: us
Total students: 30
Total teachers: 6
Total subs: 2
--
import csv
import re
search = raw_input('Enter school (e.g. us: ')
with open('data.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
school = row['school']
students = row['students']
teachers = row['teachers']
sub = row['subs']
if re.match(search, schools) is not None:
print students
That's relatively easy to do - all you need is a dict to hold group your countries, and then just add together all of the values:
import collections
import csv
result = {} # store the results
with open("data.csv", "rb") as f: # open our file
reader = csv.DictReader(f) # use csv.DictReader for convenience
for row in reader:
country = row.pop("school")[:2] # get our country
result[country] = result.get(country, collections.defaultdict(int)) # country group
for column in row: # loop through all other columns
result[country][column] += int(row[column]) # add them together
# Now you can use or print your result by country:
for country in result:
print("Country: {}".format(country))
print("Total students: {}".format(result[country].get("students", 0)))
print("Total teachers: {}".format(result[country].get("teachers", 0)))
print("Total subs: {}\n".format(result[country].get("subs", 0)))
This is also universal as you can add additional number columns (e.g. janitors :D) and it will happily sum them together, but keep in mind that it works only with integers (if you want floats, replace the references to int with float) and it expects that every field except school is a number.
Your problem could be solved with something like this:
import csv
search = raw_input('Enter school (e.g. us: ')
with open('data.csv') as csvfile:
reader = csv.DictReader(csvfile)
result_countrys = {}
for row in reader:
students = int(row['students'])
teachers = int(row['teachers'])
subs = int(row['subs'])
subs = row['subs']
country = school[: 2]
if country in result_countrys:
count = result_countrys[country]
count['students'] = count['students'] + students
count['teachers'] = count['teachers'] + teachers
count['subs'] = count['subs'] + subs
else :
dic = {}
dic['students'] = students
dic['teachers'] = teachers
dic['subs'] = subs
result_countrys[country] = dic
for k, v in result_countrys[search].iteritems():
print("country " + str(search) + " has " + str(v) + " " + str(k))
I tryed out with this set of values:
reader = [{'school': 'us-school1', 'students': 20, 'teachers': 6, 'subs': 2}, {'school': 'us-school2', 'students': 20, 'teachers': 6, 'subs': 2}, {'school': 'uk-school1', 'students': 20, 'teachers': 6, 'subs': 2}]
and the result is:
Enter school (e.g. us): us
country us has 30 students
country us has 6 teachers
country us has 2 subs

python: Finding min values of subsets of a list

I have a list that looks something like this
(The columns would essentially be acct, subacct, value.):
1,1,3
1,2,-4
1,3,1
2,1,1
3,1,2
3,2,4
4,1,1
4,2,-1
I want update the list to look like this:
(The columns are now acct, subacct, value, min of the value for each account)
1,1,3,-4
1,2,-4,-4
1,3,1,-4
2,1,1,1
3,1,2,2
3,2,4,2
4,1,1,-1
4,2,-1,-1
The fourth value is derived by taking the min(value) for each account. So, for account 1, the min is -4, so col4 would be -4 for the three records tied to account 1.
For account 2, there is only one value.
For account 3, the min of 2 and 4 is 2, so the value for col 4 is 2 where account = 3.
I need to preserve col3, as I will need to use the value in column 3 for other calculations later. I also need to create this additional column for output later.
I have tried the following:
with open(file_name, 'rU') as f: #opens PW file
data = zip(*csv.reader(f, delimiter = '\t'))
# data = list(list(rec) for rec in csv.reader(f, delimiter='\t'))
#reads csv into a list of lists
#print the first row
uniqAcct = []
data[0] not in used and (uniqAcct.append(data[0]) or True)
But short of looping through and matching on each unique count and then going back through and adding a new column, I am stuck. I think there must be a pythonic way of doing this, but I cannot figure it out. Any help would be greatly appreciated!
I cannot use numpy, pandas, etc as they cannot be installed on this server yet. I need to use just basic python2
So the problem here is your data structure, it's not trivial to index.
Ideally you'd change it to something readible and keep it in those containers. However if you insist on changing it back into tuples I'd go with this construction
# dummy values
data = [
(1, 1, 3),
(1, 2,-4),
(1, 3, 1),
(2, 1, 1),
(3, 1, 2),
(3, 2, 4),
(4, 1, 1),
(4, 2,-1),
]
class Account:
def __init__(self, acct):
self.acct = acct
self.subaccts = {} # maps sub account id to it's value
def as_tuples(self):
min_value = min(val for val in self.subaccts.values())
for subacct, val in self.subaccts.items():
yield (self.acct, subacct, val, min_value)
def accounts_as_tuples(accounts):
return [ summary for acct_obj in accounts.values() for summary in acct_obj.as_tuples() ]
accounts = {}
for acct, subacct, val in data:
if acct not in accounts:
accounts[acct] = Account(acct)
accounts[acct].subaccts[subacct] = val
print(accounts_as_tuples(accounts))
But ideally, I'd keep it in the Account objects and just add a method that extracts the minimal value of the account when it's needed.
Here is another way using your initial approach.
Modify the way you import your data, so you can easily handle it in python.
import csv
mylist = []
with open(file_name, 'rU') as f: #opens PW file
data = csv.reader(f, delimiter = '\t')
for row in data:
splitted = row[0].split(',')
# this is in case you need integers
splitted = [int(i) for i in splitted]
mylist += [splitted]
Then, add the fourth column
updated = []
for acc in set(zip(*mylist)[0]):
acclist = [x for x in mylist if x[0] == acc]
m = min(i for sublist in acclist for i in sublist)
[l.append(m) for l in acclist]
updated += acclist

Complex Django Query to Create Dictionary

models.py
class Event(models.Model):
name = models.CharField(max_length=100)
date = models.DateField()
class Result(models.Model):
event = models.ForeignKey(Event)
place = models.IntegerField()
person = models.CharField(max_length=100)
gender = models.CharField(max_length=1)
score = models.IntegerField()
Event sample data:
id, name, date
1, 'event1', '2015-01-01'
2, 'event2', '2015-02-01'
3, 'event3', '2015-03-01'
Result sample data:
event_id, place, person, gender, score
1, 1, 'al', 'M', 25
1, 2, 'bob', 'M', 22
1, 3, 'cindy', 'F', 21
1, 4, 'doug', 'M', 20
2, 1, 'elen', 'F', 30
2, 2, 'frank', 'M', 28
2, 3, 'gord', 'M', 20
2, 4, 'helen', 'F', 19
I want to query this and get a dictionary containing the male and female winners (with scores) for each event:
winnersdict = {event_id: (mwinner, mscore, fwinner, fscore), ...}
In this case the resulting dictionary would be:
{1: ('al', 25, 'cindy', 21), 2: ('frank', 28, 'elen', 30). 3: (None, None, None, None)}
Right now I am doing it like this:
events = Event.objects.all().order_by('date')
winnersdict = {}
for e in events:
femalewinner = Result.objects.filter(event_id=e.id, gender='F')[:1]
if len(femalewinner) == 0:
fwinner = None
fscore = None
else:
fwinner = femalewinner[0].person
fscore = femalewinner[0].score
malewinner = Result.objects.filter(event_id=e.id, gender='M')[:1]
if len(malewinner) == 0:
mwinner = None
mscore = None
else:
mwinner = malewinner[0].person
mscore = malewinner[0].score
winnersdict[e.id] = (mwinner, mscore, fwinner, fscore)
Surely there is a smarter way. I'm going to have thousands of events, looping through this way seems terrible. If it simplified things I would also be fine with generating a separate femalewinnersdict and malewinnersdict. I'm also fine (might even prefer) if we leave the None's out of the resulting dictionary, for this case I'm not interested in events that don't have results yet.
Any ideas?
Please try following query, it would give you male/female separately.
from django.db.models import Max
male_results = Event.objects.filter(result__gender='M') \
.annotate(max_score=Max('result__score')) \
.values('name', 'result__person', 'result__score')