Question paper · SQA assessment guidance

Higher Question Paper Guide

A pupil-friendly guide to the 80-mark question paper: what is assessed, how the paper is structured, how marks are actually awarded, and real candidate answers showing exactly where marks are won and lost.

80 marks 2 hours Closed book May 2027
80

The question paper is worth 80 marks out of the 160 marks available for the whole course — exactly half.

2h

You sit it under closed-book exam conditions in one sitting, in May, at the end of the course.

1+1

Everyone attempts Section 1 (SDD and Computer Systems), then answers Section 2 questions for either DDD or WDD.

Important: the marked examples on this page come from the publicly released 2019 question paper candidate evidence and commentary. Several 2019 candidates answered "using a programming language of your choice" in Visual Basic-style pseudocode or the SQA Reference Language rather than Python. Today's SDD unit is taught entirely in Python, so write your own exam answers in Python — but the marking principle shown throughout this page is identical either way: markers credit the underlying concept (the right starting value, the right loop, the right condition, the right join) in whatever correct notation you use, not one specific syntax.

Two sections, one mandatory and one choice.

The question paper tests knowledge and skills from across the course through short-answer, structured and extended-response questions. Some questions ask you to state or explain a concept; others ask you to complete or design part of a solution — a data-flow table, an algorithm, a query, an HTML element — using a notation of your choice.

Mandatory · everyone attempts

Section 1 · SDD & Computer Systems

55 marks
Software Design & Development

Standard algorithms, data structures, parameter passing, data-flow design, file handling, and tracing/explaining code — usually the larger share of Section 1.

Computer Systems

Data representation, computer architecture, the fetch-execute cycle, performance factors, and the impact and legislation topics.

Option

Section 2 · Database

25 marks

Query design tables, SQL statements (joins, aggregate functions, GROUP BY, sorting), and data dictionary or ER diagram questions.

Option

Section 2 · Web

25 marks

HTML elements, CSS rules, and JavaScript functions and event handlers, usually built around editing or extending a given page.

Marks are awarded positively, bullet point by bullet point.

Question paper marking instructions break most multi-mark questions into explicit bullet points — one idea, one mark. You don't need to hit every bullet with a perfectly polished answer; you need to show each idea clearly enough that a marker can tick it off. The flip side is equally true: a confident, fluent-looking answer that skips one bullet point still loses that mark, however good the rest of it is.

CommandWhat markers are looking forWeak answer pattern
StateA short, correct fact — no working or justification needed.An answer that drifts into explaining "why" when only "what" was asked for.
CompleteFill in exactly what's missing, consistent with the parts of the table, diagram or code already given.Repeating or restating data that's already provided elsewhere in the question, rather than the specific missing piece.
DesignUse a recognised design technique (pseudocode, a flowchart, or the SQA Reference Language) that covers every step precisely, in the right order.Skipping the initial/setup step, or leaving a condition or comparison implied rather than written out.
Define / DeclareThe exact construct asked for — a record structure, an array, a variable — with a correct name, fields and data types.Declaring the right idea without a data type, or naming a field differently from how it's used later.
WriteWorking code or SQL that does exactly what's described — every clause included, not just the core idea.SQL that gets the calculation right but drops a clause such as FROM or GROUP BY.
ExplainDescribe what specific lines do using the actual values at that point — a trace, not a summary.Explaining what the code does in general, without ever referencing the iteration or values the question asked about.
Concept over syntax: the same design question in the 2019 evidence was answered correctly in Visual Basic-style pseudocode, in Python, in the SQA Reference Language, and as a flowchart — and every one of those correct answers earned full marks. Markers are trained to credit the idea, not a specific language. Pick whichever notation you're fastest and most accurate in.

Real candidates, the same 2019 question paper, very different marks on the same question.

The cards below compare real candidate responses to the same question from the 2019 Higher question paper. None of these candidates is "the good one" — the same candidate scores full marks on one question and zero on the next. That's the real lesson: marks are awarded question by question, bullet point by bullet point, not on how strong an answer looks overall.

SDD · Pre-defined functions

A substring operation is marked index by index — one wrong number loses the mark.

Response 11 / 2

mid(month,1,3) & mid(year,3,1)

1 mark — the first substring is correct (characters 1–3 of month give "Apr"), but the second substring operation is incorrect: mid(year,3,1) only takes one character starting at position 3 ("1"), not the two characters needed for "19".

Candidate Response 1's handwritten substring answer
🔍 View original answer
Response 22 / 2

shortDate = month[0:3] + year[2:4]

2 marks — full marks. The indexes on both substrings are consistent: month[0:3] gives "Apr" and year[2:4] gives "19", matching Python's zero-indexed slicing exactly.

Candidate Response 2's handwritten substring answer
🔍 View original answer
Computer Systems · Fetch-execute cycle

Fetch-execute steps are marked on which bus is named and which direction data moves.

Response 11 / 2

Step 2: "The processor activates the read line on the control bus." Step 3: "Instruction is sent to memory location using the data bus and then saved in the instruction register."

1 mark — step 2 correctly names the control bus. Step 3 has the data moving the wrong way: an instruction travels from memory to the processor along the data bus, not out to memory.

Candidate Response 1's fetch-execute cycle answer
🔍 View original answer
Response 20 / 2

Step 2: "Read line is activated thereby transferring instructions to Memory Data Register." Step 3: "Instructions get passed to instruction register from Memory Data register."

0 marks — step 2 never names the control bus or unit responsible for activating the read line, and step 3 never mentions the data bus at all — it only describes movement inside the processor.

Candidate Response 2's fetch-execute cycle answer
🔍 View original answer
SDD · Records & arrays of records

A record needs a name and every field — an array of records is marked for matching that name exactly.

Both responses below scored full marks — they're shown side by side not as right-vs-wrong, but as two completely different, equally valid ways to answer the same question.

Response 14 / 4
(i) Record structure2/2

Structure SampleData Dim Speed As Real Dim accelerator As Integer Dim brake As Integer Dim seatbelt As Boolean End Structure

Candidate Response 1's record structure
🔍 View original
(ii) Array of records2/2

Dim Cars(200) As SampleData

Candidate Response 1's array of records
🔍 View original

Full marks — a named record structure with all four fields, then an array declared using that exact record name as its data type.

Response 24 / 4
(i) Record structure2/2

RECORD event IS { REAL speed; INTEGER accelerator; INTEGER brake; BOOLEAN seatbeltOn; }

Candidate Response 2's record structure in SQA Reference Language
🔍 View original
(ii) Array of records2/2

DECLARE readings AS ARRAY OF event INITIALLY []

Candidate Response 2's array of records in SQA Reference Language
🔍 View original

Full marks — the same pattern in the SQA Reference Language: a named record with four fields, then an array of that record type.

SDD · Standard algorithm — find maximum

A "find the maximum" algorithm needs an appropriate starting value, a full traversal, and a correct comparison — in any notation.

Response 14 / 4

1. Set Max to first value in Cars.speed array 2. Initialise loop counter to 199 3. Compare Max with Cars(counter).Speed 4. Set Max to Cars(counter).Speed if Max is less 5. Return value after loop of 2–4 is finished

4/4 — the maximum starts at an appropriate value (the first element), the loop traverses the whole array, and the comparison and reassignment are both present, even though step 4 folds the If condition and the reassignment into a single line.

Candidate Response 1's find-maximum algorithm design
🔍 View original answer
Response 24 / 4

maxSpeed = -1 for index in range(200): if readings[index].speed > maxSpeed: maxSpeed = readings[index].speed

4/4 — the same four ideas expressed as working Python. Marking instructions credit the concept, not a specific language, so a correct program earns exactly the same marks as a correct pseudocode design.

Candidate Response 2's find-maximum algorithm in Python
🔍 View original answer
Database · Functional requirements

A functional requirement names the query the database must support — not the scenario's own wording read back.

Response 10 / 2

"Fundraisers must be able to see their total donations." "Animal Help must be able to see the funds for each fundraiser."

0/2 — both requirements restate the end-user needs already given in the question stem, not the underlying query the database has to run.

Candidate Response 1's functional requirements answer
🔍 View original
Response 22 / 2

"Calculate a query to show the sum of all the donations of a certain fundraiser (by sponsor)." "Show a query of all funds raised for a certain charity (Animal Help)."

2/2 — both requirements identify the actual underlying query, not just the end-user need behind it.

Candidate Response 2's functional requirements answer
🔍 View original
Response 32 / 2

"Must be able to sum all donations from a specific person." "Must be able to sum all donation values in the database."

2/2 — awarded for identifying the functions the database needs to perform, inferred from the question stem rather than copied from it.

Candidate Response 3's functional requirements answer
🔍 View original
Database · SQL — aggregate function

An SQL answer is marked clause by clause — a missing FROM costs a mark even when the calculation is right.

Response 11 / 3

SELECT fundraiserID, AVG(amount) AS [Average donation (£)] WHERE fundraiser.fundraiserID = donation.fundraiserID

1/3 — fundraiserID is selected and AVG is applied to the correct field, and the alias is correct, but there's no FROM clause naming the tables, so the second mark isn't awarded.

Candidate Response 1's SQL average donation query
🔍 View original
Response 22 / 3

SELECT fundraiserID, (SUM(amount)/COUNT(fundraiserID)) AS [Average donation (£)] FROM Donation, fundraiser WHERE Donation.fundraiserID = fundraiser.fundraiserID

2/3 — SUM divided by COUNT is an accepted alternative to AVG, and the alias and FROM with the correct tables are both present. The third mark needs GROUP BY, which isn't included.

Candidate Response 2's SQL average donation query
🔍 View original
Response 33 / 3

SELECT fundraiserID, SUM(amount)/COUNT(amount) AS [Average donation(£)] FROM Fundraiser, Donation WHERE Fundraiser.fundraiserID = Donation.fundraiserID GROUP BY fundraiserID ORDER BY fundraiserID ASC

3/3 — full marks, despite joining two tables when the query could have run from Donation alone. A working, correctly structured query is credited even when it isn't the most efficient route to the answer.

Candidate Response 3's SQL average donation query
🔍 View original
SDD · Data-flow design

A data-flow answer only lists what a step genuinely needs in and out — not everything that's available.

Response 10 / 2

Step 2 — IN: hotelname[], stars[], price[] OUT: position[]

0/2 — hotelname[] isn't needed to find the position of the cheapest 5-star hotel, so it shouldn't be in the IN data flow, and position should be a single value, not an array — position[] incorrectly annotates it as one.

Candidate Response 1's data-flow table
🔍 View original
Response 21 / 2

Step 2 — IN: hotelname[], stars[], price[] OUT: position

1/2 — the OUT data flow (position, without array brackets) is now correct, earning that mark, but IN still carries the same unneeded hotelname[], so the IN mark isn't awarded.

Candidate Response 2's data-flow table
🔍 View original
SDD · Algorithm design

Five design marks map onto five separate ideas — missing just one caps a design at 4/5 however it's written.

Response 14 / 5

position = 0 price = 5000000 loop for the length of stars[] if stars[index] equals to 5 then if price[index] < price set price to price[index] set position to index end if end if return position

4/5 — both If conditions are correct, price is reassigned correctly within the If, and position is correctly assigned within the If. All of that is credited even though the comparison and the reassignment share one line, after an earlier attempt was crossed out.

Candidate Response 1's design for finding the cheapest five-star hotel
🔍 View original answer
Response 24 / 5

Flowchart: initialise position as 0, initialise min as price(0) → loop counter 1 to length → is stars(counter) = 5? → is price(counter) < min? → set min as price(counter), set position as counter.

4/5 — the same four ideas as Response 1, this time as a flowchart, reassigning "min" instead of "price". Different notation, identical mark.

Candidate Response 2's flowchart for finding the cheapest five-star hotel
🔍 View original answer
SDD · Parallel 1D arrays

Declaring parallel arrays is marked for both existence and data type — three arrays with no type only earns half marks.

Response 11 / 2

Declare names AS Array*200 Initially Declare rank As Array*200 Initially Declare scores Array*200 Initially

1/2 — three arrays have been declared, after several crossed-out attempts, but none states a data type, so only the first mark is awarded.

Candidate Response 1's parallel array declarations
🔍 View original
Response 22 / 2

name = [""] * 200 category = [""] * 200 score = [0] * 200

2/2 — three arrays, and each one's data type is implied correctly by its initial value: empty strings for the text fields, zero for the numeric score.

Candidate Response 2's parallel array declarations in Python
🔍 View original
SDD · Standard algorithm — count with two conditions

Counting matches needs both conditions checked together — a single condition caps the mark even with everything else correct.

Response 15 / 5

target = input(...) NumFound = 0 for score in scores: if category[score] == "Junior" AND scores[score] >= target: NumFound = NumFound + 1 print(...)

5/5 — NumFound is both initialised and incremented, the loop traverses the array, both conditions (category AND score) are present, and the output is concatenated correctly.

Candidate Response 1's counting algorithm in Python
🔍 View original
Response 24 / 5

score = InputBox(...) FOR index 0 TO 199 DO IF performance(index) >= score THEN qualifiers = qualifiers + 1 END IF END FOR msgbox(...)

4/5 — qualifiers is initialised and the loop is correct, but only the score condition is tested — there's no check that the competitor is actually a Junior, so one condition mark is lost.

Candidate Response 2's counting algorithm in VB-style pseudocode
🔍 View original
Response 34 / 5

min = int(input(...)) count = 0 for i in range(200): if score[i] >= min: count += 1 print(...)

4/5 — the same gap as Response 2: only the score condition is tested, with no category check, so one condition mark is lost even though everything else is correct.

Candidate Response 3's counting algorithm in Python
🔍 View original
Response 42 / 5

qualifyingScore = InputBox(...) count = 0 FOR i = 0 To 199 If category(i) = "Junior" AND scores(i) >= qualifyingScore Then count = count + 1 End If Next i Msgbox("i & ...")

2/5 — count is initialised and incremented, the loop is correct, and both conditions are present, worth 2 of the 5 marks — but the final message outputs the loop variable i instead of count, so the output isn't correctly concatenated.

Candidate Response 4's counting algorithm in VB-style pseudocode
🔍 View original
Web · JavaScript mouse-out event

Resetting an image on mouse-out needs the right image, the right function call, and the right event name — each is checked separately.

Response 2 answered both part (i) and part (ii) inside the same box, so the same original page is used for both quotes below.

Response 12 / 4
(i) The function1/2

function rollaway(my_image) {my_image.src = '../images/Bailey2.png';}

Candidate Response 1's rollaway function
🔍 View original

1/2 — a function with the correct name and parameter, but it resets the image to the wrong file: Bailey2.png, not the original image.

(ii) The HTML element1/2

onmouseout = "rollaway(this)"

Candidate Response 1's HTML element calling rollaway
🔍 View original

1/2 — the function is called correctly with the right event, but the question asked for the whole HTML element to be re-written, not just the added attribute, so the second mark isn't awarded.

Response 23 / 4
(i) The function2/2

<img id="dogImage" src="../images/Bailey1.png" onmouseover="rollover(this)" onmouseoff="rolloff(this)">

Candidate Response 2's combined HTML answer
🔍 View original

2/2 — the function name, parameter, and the source attribute pointing to the correct original image (Bailey1.png) are all present.

(ii) The HTML element1/2

onmouseoff = "rolloff(this)"

Candidate Response 2's combined HTML answer
🔍 View original

1/2 — the function is correctly called with the right parameter, but the event name is wrong: onmouseoff isn't a real mouse event — it needed to be onmouseout.

Database · Query design

A query design table is marked field by field — a correct join and grouping still lose a mark if the calculation targets the wrong column.

Response 12 / 3

Field(s): forename, surname, SUM(time) Search criteria: Instructor.instructorID = Booking.instructorID AND date = ??/05/2019 Grouping: forename, surname

2/3 — the search criteria and grouping are both correct, but SUM is applied to the wrong field — "time" — rather than the lesson duration field being summed.

Candidate Response 1's query design table
🔍 View original
Response 21 / 3

Field(s): forename, surname, Total(time) as Maxhours Search criteria: WHERE Customer.customerID = Booking.customerID AND date = "*/05/2019" Grouping: customerID

1/3 — the search criteria is correct, but the function name and the grouping are both wrong: "Total" isn't a recognised aggregate function, and grouping by customerID instead of the forename/surname fields loses the grouping mark.

Candidate Response 2's query design table
🔍 View original
Database · Query design

Query design credits are earned one row of the table at a time — using SUM instead of COUNT still leaves marks on the table.

Response 12 / 4

Field(s): forename, surname, Sum(lessonDuration) Table(s): Instructor, Booking Grouping: forename, surname

2/4 — the tables and grouping are both correct, but SUM was used instead of COUNT to count lessons booked, and no sort order was given, so those two marks are lost.

Candidate Response 1's query design table for lessons per instructor
🔍 View original
Response 22 / 4

Field(s): forename, surname, COUNT(instructorID) as [mostLessons] Table(s): Instructor, Booking Grouping: instructorID Sort order: [mostLessons] DESC

2/4 — the fields, COUNT and tables are all correct. Grouping by instructorID rather than the forename/surname fields the design table lists loses that mark, though the sort order on the alias, descending, is still credited since this is a design question, not a syntax check.

Candidate Response 2's query design table for lessons per instructor
🔍 View original
SDD · Trace & explain code

Explaining code needs the actual values on a specific iteration — describing what the code does in general isn't enough.

Response 10 / 2

"The program is comparing the list to the newlist and if they are not equal to one another then the position is incremented, which then sets the list and newlist to be equal."

0/2 — this restates the code as a sentence but never refers to the first iteration, or to the actual values of the variables during it, which the question specifically asked for.

Candidate Response 1's explanation of the code
🔍 View original
Response 21 / 2

"This will only add the value to the newlist if the value has not already been entered. If the value in the original list is not equal to the last value (the newest in newlist), then it will increment the counter and add it to the newlist array."

1/2 — a meaningful description of what the code is for, earning one mark, but it still never references the relevant values during the first iteration specifically.

Candidate Response 2's explanation of the code
🔍 View original
How to use these: cover the "why" text first and decide what mark you'd give. Then reveal it and compare your judgement with the marker's actual reasoning.

Patterns worth practising, drawn directly from the marking above.

Structured & design questions

  • Only include what a step genuinely needs in a data-flow or design answer — extra "just in case" data can lose a mark, not just waste time.
  • Write out every step of a recognised design technique, including the setup/initial-value step, even when it feels obvious.
  • Pick pseudocode, a flowchart, or real code — whichever you're fastest and most accurate in. All three earn identical marks for the same idea.

SQL & query design

  • Include every clause — SELECT, FROM, WHERE, GROUP BY, ORDER BY — even when the calculation itself is already correct.
  • Group by the same fields that are selected alongside an aggregate function, not just any field that happens to be unique.
  • State functional requirements as the query the database needs to run, not the end-user need already given in the question.

Explaining & tracing code

  • When asked to explain specific lines "during the first iteration", reference the actual values at that point — not a general summary of what the code does.
  • Name the exact bus, register or unit involved, and get the direction of data flow right — "sent to memory" and "read from memory" are not interchangeable.
  • Check every condition a question implies is needed — a count that only tests one of two stated conditions loses a mark even if the rest of the logic is perfect.
Best preparation routine: work through past-paper questions one bullet point at a time. After answering, check your response against the marking instructions line by line, not just against whether your final answer "looks right" — that's exactly how these markers are scoring you.

Documents used to build this guide

Course specification

Used for the official question paper structure, marks, timing, and the skill areas assessed.

Open local PDF

2019 Understanding Standards question paper commentary

Used for every mark breakdown and marker reasoning shown in the marked examples section above.

Open local PDF

2019 Understanding Standards question paper candidate evidence

Used for every candidate quote and scanned answer shown in the marked examples section above.

Open local PDF

Understanding Standards — official page

The live SQA page hosting these and other question paper exemplars for Higher Computing Science.

Open official page