{"id":29178463,"url":"https://github.com/nph1508/sql_for_ecommerce_analyzing_sales_customer_behavior_in_bigquery","last_synced_at":"2025-07-01T19:03:45.185Z","repository":{"id":299378242,"uuid":"1002828025","full_name":"nph1508/SQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery","owner":"nph1508","description":"Designed and executed complex SQL queries on an ecommerce dataset using Google BigQuery to uncover customer behavior patterns, sales performance, and category-level insights. Focused on extracting business value through data exploration and aggregation techniques.","archived":false,"fork":false,"pushed_at":"2025-06-30T03:30:54.000Z","size":69,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-30T03:36:09.406Z","etag":null,"topics":["analysis","bigquery","sql"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nph1508.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-16T07:54:26.000Z","updated_at":"2025-06-30T03:30:58.000Z","dependencies_parsed_at":"2025-06-30T03:36:16.600Z","dependency_job_id":"8eb86d96-e1ee-42cd-801e-2ec080c1f1f6","html_url":"https://github.com/nph1508/SQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery","commit_stats":null,"previous_names":["nph1508/test","nph1508/sql_e-commerce_dataset","nph1508/sql_for_ecommerce_analyzing_sales_customer_behavior_in_bigquery"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nph1508/SQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nph1508%2FSQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nph1508%2FSQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nph1508%2FSQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nph1508%2FSQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nph1508","download_url":"https://codeload.github.com/nph1508/SQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nph1508%2FSQL_for_Ecommerce_Analyzing_Sales_Customer_Behavior_in_BigQuery/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263021815,"owners_count":23401148,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analysis","bigquery","sql"],"created_at":"2025-07-01T19:01:04.217Z","updated_at":"2025-07-01T19:03:45.168Z","avatar_url":"https://github.com/nph1508.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# SQL for Ecommerce: Analyzing Sales \u0026 Customer Behavior in BigQuery\nAuthor: Nguyễn Phương Huy\n\nDate: 2000-15-08\n\nTools Used: SQL\n## 📑 Table of Contents\n1. [📌 Background \u0026 Overview](#-background--overview)\n2. [📂 Dataset Description \u0026 Data Structure](#-dataset-description--data-structure)\n3. [🔎 Final Conclusion \u0026 Recommendations](#-final-conclusion--recommendations)\n## 📌 Background \u0026 Overview\n🎯 Objective\n📖 This project uses SQL (BigQuery) to analyze an ecommerce dataset in order to:\n\n✔️ Uncover trends in sales performance across product categories and time periods\n\n✔️ Analyze customer behavior patterns, including frequency and purchase volume\n\n✔️ Identify top-performing products and underperforming segments\n\n✔️ Provide data-driven insights to support inventory, marketing, and sales decisions\n\n💡 Main Business Questions:\n\nWhat are the best-selling product categories over time?\n\nWhich customers contribute most to total revenue?\n\nAre there seasonal patterns in customer purchasing behavior?\n\nHow can we segment customers based on their purchase activity?\n\n👤 Who is this project for?\n\n✔️ Data Analysts seeking to practice SQL in a real-world ecommerce context\n\n✔️ Business Analysts / Ecommerce Teams needing insights to optimize operations and marketing\n\n✔️ Decision-Makers who want to understand customer dynamics and product performance\n\n## 📂 Dataset Description \u0026 Data Structure\n### 📌 Data Source\n\n- **Source:** [Google Analytics Sample Dataset](https://console.cloud.google.com/marketplace/product/bigquery-public-data/google-analytics-sample)  \n- **Size:** ~400,000 rows × 15+ columns  \n- **Format:** BigQuery table (`.sql`)\n\n### 📊 Data Structure \u0026 Relationships**\n\n1️⃣ Tables Used:\u003cdetails\u003e\n  \u003csummary\u003e📋 Click to view \u003c/summary\u003e\n\n| Field Name | Data Type | Description |\n| --- | --- | --- |\n| fullVisitorId | STRING | The unique visitor ID. |\n| date | STRING | The date of the session in YYYYMMDD format. |\n| totals | RECORD | This section contains aggregate values across the session. |\n| totals.bounces | INTEGER | Total bounces (for convenience). For a bounced session, the value is 1, otherwise it is null. |\n| totals.hits | INTEGER | Total number of hits within the session. |\n| totals.pageviews | INTEGER | Total number of pageviews within the session. |\n| totals.visits | INTEGER | The number of sessions (for convenience). This value is 1 for sessions with interaction events. The value is null if there are no interaction events in the session. |\n| totals.transactions | INTEGER | Total number of ecommerce transactions within the session. |\n| trafficSource.source | STRING | The source of the traffic source. Could be the name of the search engine, the referring hostname, or a value of the utm_source URL parameter. |\n| hits | RECORD | This row and nested fields are populated for any and all types of hits. |\n| hits.eCommerceAction | RECORD | This section contains all of the ecommerce hits that occurred during the session. This is a repeated field and has an entry for each hit that was collected. |\n| hits.eCommerceAction.action_type | STRING | The action type. Click through of product lists = 1, Product detail views = 2, Add product(s) to cart = 3, Remove product(s) from cart = 4, Check out = 5, Completed purchase = 6, Refund of purchase = 7, Checkout options = 8, Unknown = 0.\u003cbr\u003eUsually this action type applies to all the products in a hit, with the following exception: when hits.product.isImpression = TRUE, the corresponding product is a product impression that is seen while the product action is taking place (i.e., a \"product in list view\").\u003cbr\u003eExample query to calculate number of products in list views:\u003cbr\u003eSELECT\u003cbr\u003eCOUNT(hits.product.v2ProductName)\u003cbr\u003eFROM [foo-160803:123456789.ga_sessions_20170101]\u003cbr\u003eWHERE hits.product.isImpression == TRUE\u003cbr\u003eExample query to calculate number of products in detailed view:\u003cbr\u003eSELECT\u003cbr\u003eCOUNT(hits.product.v2ProductName),\u003cbr\u003eFROM\u003cbr\u003e[foo-160803:123456789.ga_sessions_20170101]\u003cbr\u003eWHERE\u003cbr\u003ehits.ecommerceaction.action_type = '2'\u003cbr\u003eAND ( BOOLEAN(hits.product.isImpression) IS NULL OR BOOLEAN(hits.product.isImpression) == FALSE ) |\n| hits.product | RECORD | This row and nested fields will be populated for each hit that contains Enhanced Ecommerce PRODUCT data. |\n| hits.product.productQuantity | INTEGER | The quantity of the product purchased. |\n| hits.product.productRevenue | INTEGER | The revenue of the product, expressed as the value passed to Analytics multiplied by 10^6 (e.g., 2.40 would be given as 2400000). |\n| hits.product.productSKU | STRING | Product SKU. |\n| hits.product.v2ProductName | STRING | Product Name. |\n\n\u003c/details\u003e\n\n2️⃣Table Schema: https://support.google.com/analytics/answer/3437719?hl=en\n\n## ⚒️Main Process\n### Query 01: Calculate total visit, pageview, transaction for Jan, Feb and March 2017 (order by month)\n**Purpose:** Aggregates 3 key metrics (visits, pageviews, transactions) by month (Jan–Mar 2017).  \n**Goal:** Detect seasonal performance trends and identify which months bring better engagement.\n```sql\nselect \n  format_date('%Y%m',parse_date('%Y%m%d', `date`)) as month,\n  count(totals.visits) as visits,\n  sum(totals.pageviews) as pageviews,\n  sum(totals.transactions) as transactions\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_2017*`\nwhere _table_suffix between '0101' and '0331'\ngroup by month\norder by month;\n```\n** ✅ Results:** \n| month   | visits | pageviews | transactions |\n|---------|--------|-----------|--------------|\n| 201701  | 64,694 | 257,708   | 713          |\n| 201702  | 62,192 | 233,373   | 733          |\n| 201703  | 69,931 | 259,522   | 993          |\n\n**📝 Observation:** The table shows monthly aggregated metrics. March (201703) demonstrates an improvement across all key indicators—visits, pageviews, and transactions—compared to January and February.\n### Query 02: Bounce rate per traffic source in July 2017 (Bounce_rate = num_bounce/total_visit) (order by total_visit DESC)\n**Purpose:** Calculates bounce rate = bounces / visits per source.  \n**Goal:** Evaluate traffic quality by source and identify underperforming channels.\n```sql\nselect\n    trafficSource.source as source,\n    sum(totals.visits) as total_visits,\n    sum(totals.bounces) as total_no_of_bounces,\n    round((sum(totals.bounces)/sum(totals.visits))* 100.00,2) as bounce_rate\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201707*`\ngroup by source\norder by total_visits DESC;\n```\n** ✅ Results:** \n| source | total_visits | total_no_of_bounces | bounce_rate |\n| ------ | ------------ | ------------------- | ----------- |\n| google | 38400 | 19798 | 51.56 |\n| (direct) | 19891 | 8606 | 43.27 |\n| youtube.com | 6351 | 4238 | 66.73 |\n| analytics.google.com | 1972 | 1064 | 53.96 |\n| Partners | 1788 | 936 | 52.35 |\n| m.facebook.com | 669 | 430 | 64.28 |\n| google.com | 368 | 183 | 49.73 |\n| dfa | 302 | 124 | 41.06 |\n| sites.google.com | 230 | 97 | 42.17 |\n| facebook.com | 191 | 102 | 53.4 |\n\n**📝 Observation:** Google and direct traffic are the main sources by volume, while platforms like Reddit and mail.google.com show significantly lower bounce rates.\n### Query 3: Revenue by traffic source by week, by month in June 2017\n**Purpose:** Shows revenue distribution by traffic source, split by month and week.  \n**Goal:** Understand financial contribution and fluctuations per source over time.\n```sql\nselect \n    'month' as time_type,\n    format_date('%y%m', date(parse_date('%y%m%d', date))) as time,\n    trafficsource.source as source,\n    sum(product.productrevenue) / 1000000 as revenue\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201706*`,\nunnest(hits) as hit,\nunnest(hit.product) as product\nwhere product.productRevenue is not null\ngroup by time, source\n\nunion all \n\nselect\n    'week' as time_type,\n    format_date('%y%w', date(parse_date('%y%m%d', date))) as time,\n    trafficsource.source as source,\n    sum(product.productRevenue) / 1000000 as revenue\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201706*`,\nunnest(hits) as hit,\nunnest(hit.product) as product\nwhere product.productRevenue is not null\ngroup by time, source\n\norder by time_type, revenue desc;\n```\n#### ✅ Results:\n| time_type | time | source | revenue |\n| --- | --- | --- | --- |\n| Month | 201706 | (direct) | 97,333.62 |\n| Month | 201706 | google | 18,757.18 |\n| Month | 201706 | dfa | 8,862.23 |\n| Month | 201706 | mail.google.com | 2,563.13 |\n| Month | 201706 | search.myway.com | 105.939998 |\n| Week | 201724 | (direct) | 30,908.91 |\n| Week | 201725 | (direct) | 27,295.32 |\n| Week | 201723 | (direct) | 17,325.68 |\n| Week | 201726 | (direct) | 14,914.81 |\n| Week | 201724 | google | 9,217.17 |\n\n**📝 Observation:** Direct traffic drives the most revenue both monthly and weekly. Google and DFA are also top-performing sources, but with lower contribution.\n### Query 04: Average number of pageviews by purchaser type (purchasers vs non-purchasers) in June, July 2017.\n**Purpose:** Compares user engagement across groups based on purchase behavior (June–July 2017).  \n**Goal:** Identify browsing behavior and its correlation with conversion.\n```sql\nwith \npurchaser_data as(\n  select\n      format_date(\"%Y%m\",parse_date(\"%Y%m%d\",date)) as month,\n      round((sum(totals.pageviews)/count(distinct fullVisitorId)),2) as avg_pageviews_purchase,\n  from `bigquery-public-data.google_analytics_sample.ga_sessions_2017*`\n    ,unnest(hits) hits\n    ,unnest(product) product\n  where _table_suffix between '0601' and '0731'\n  and totals.transactions\u003e=1\n  and product.productRevenue is not null\n  group by month\n),\n\nnon_purchaser_data as(\n  select\n      format_date(\"%Y%m\",parse_date(\"%Y%m%d\",date)) as month,\n      sum(totals.pageviews)/count(distinct fullVisitorId) as avg_pageviews_non_purchase,\n  from `bigquery-public-data.google_analytics_sample.ga_sessions_2017*`\n      ,unnest(hits) hits\n    ,unnest(product) product\n  where _table_suffix between '0601' and '0731'\n  and totals.transactions is null\n  and product.productRevenue is null\n  group by month\n)\n\nselect\n    pd.*,\n    round(avg_pageviews_non_purchase,2) as avg_pageviews_non_purchase\nfrom purchaser_data pd\nfull join non_purchaser_data using(month)\norder by pd.month; \n```\n** ✅ Results:** \n| month  | avg_pageviews_purchase | avg_pageviews_non_purchase |\n| ------ | ---------------------- | -------------------------- |\n| 201706 | 94.02                  | 316.87                     |\n| 201707 | 124.24                 | 334.06                     |\n\n**📝 Observation:** Surprisingly, non-purchasers have much higher average pageviews per user than purchasers, suggesting browsing-heavy behavior without conversion.\n### Query 05: Average number of transactions per user that made a purchase in July 2017\n**Purpose:** Measures how many transactions each buyer performs on average.  \n**Goal:** Understand user lifetime value and buying depth.\n```sql\nselect\n    format_date(\"%Y%m\",parse_date(\"%Y%m%d\",date)) as month,\n    round(\n        sum(totals.transactions)/count(distinct fullVisitorId)\n        ,3) as Avg_total_transactions_per_user\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201707*`\n    ,unnest (hits) hits,\n    unnest(product) product\nwhere  totals.transactions\u003e=1\nand product.productRevenue is not null\ngroup by month;\n```\n** ✅ Results:** \n| month  | Avg_total_transactions_per_user |\n| ------ | ------------------------------- |\n| 201707 | 4.164                           |\n\n**📝 Observation:** On average, each purchasing user completed over 4 transactions, indicating strong repeat buying behavior in July.\n### Query 06: Average amount of money spent per session. Only include purchaser data in July 2017\n**Purpose:** Calculates monetary value per session with transaction.  \n**Goal:** Estimate effectiveness of purchase sessions in terms of revenue.\n```sql\nselect\n    format_date(\"%Y%m\",parse_date(\"%Y%m%d\",date)) as month,\n    round(\n      ((sum(product.productRevenue)/sum(totals.visits))/power(10,6))\n      ,2) as avg_revenue_by_user_per_visit\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201707*`\n  ,unnest(hits) hits\n  ,unnest(product) product\nwhere product.productRevenue is not null\n  and totals.transactions\u003e=1\ngroup by month;\n```\n** ✅ Results:** \n| month  | avg_revenue_by_user_per_visit |\n| ------ | ----------------------------- |\n| 201707 | 43.86                         |\n\n**📝 Observation:** Each purchase session generated an average of $43.86 in revenue, which reflects solid value per visit from buyers.\n### Query 07: Other products purchased by customers who purchased product \"YouTube Men's Vintage Henley\" in July 2017. Output should show product name and the quantity was ordered.\n**Purpose:** Identifies other items frequently purchased with the target product.  \n**Goal:** Support cross-sell strategies and product bundling.\n```sql\nwith customers as (\n  select distinct fullVisitorId\n  from `bigquery-public-data.google_analytics_sample.ga_sessions_201707*`,\n  unnest(hits) as hits,\n  unnest(hits.product) as product\n  where product.v2ProductName = \"youtube men's vintage henley\"\n    and product.productRevenue is not null\n    and totals.transactions \u003e= 1\n)\n\nselect \n  product.v2ProductName as other_purchased_products, \n  sum(product.productQuantity) as quantity\nfrom `bigquery-public-data.google_analytics_sample.ga_sessions_201707*`,\nunnest(hits) as hits,\nunnest(hits.product) as product\njoin customers using (fullVisitorId)\nwhere product.v2ProductName != \"youtube men's vintage henley\"\n  and product.productRevenue is not null\n  and totals.transactions \u003e= 1\ngroup by product.v2ProductName\norder by quantity desc;\n```\n** ✅ Results:** \n| other_purchased_products | quantity |\n| --- | --- |\n| Google Sunglasses | 20 |\n| Google Women's Vintage Hero Tee Black | 7 |\n| SPF-15 Slim \u0026 Slender Lip Balm | 6 |\n| Google Women's Short Sleeve Hero Tee Red Heather | 4 |\n| YouTube Men's Fleece Hoodie Black | 3 |\n| Google Men's Short Sleeve Badge Tee Charcoal | 3 |\n| Crunch Noise Dog Toy | 2 |\n| Android Wool Heather Cap Heather/Black | 2 |\n| YouTube Twill Cap | 2 |\n| Recycled Mouse Pad | 2 |\n\n**📝 Observation:** Customers who bought the YouTube Henley also frequently purchased other branded apparel and accessories, especially Google Sunglasses.\n### \"Query 08: Calculate cohort map from product view to addtocart to purchase in Jan, Feb and March 2017. For example, 100% product view then 40% add_to_cart and 10% purchase. \n#### Add_to_cart_rate = number product  add to cart/number product view. Purchase_rate = number product purchase/number product view. The output should be calculated in product level.\"\n**Purpose:** Calculates add-to-cart and purchase conversion rates at product level across 3 months.  \n**Goal:** Evaluate funnel effectiveness and optimize product-level conversion.\n```sql\nwith product_data as(\nselect\n    format_date('%Y%m', parse_date('%Y%m%d',date)) as month,\n    count(case when eCommerceAction.action_type = '2' then product.v2ProductName end) as num_product_view,\n    count(case when eCommerceAction.action_type = '3' then product.v2ProductName end) as num_add_to_cart,\n    count(case when eCommerceAction.action_type = '6' and product.productRevenue is not null then product.v2ProductName end) as num_purchase\nFROM `bigquery-public-data.google_analytics_sample.ga_sessions_*`\n,UNNEST(hits) as hits\n,UNNEST (hits.product) as product\nwhere _table_suffix between '20170101' and '20170331'\nand eCommerceAction.action_type in ('2','3','6')\ngroup by month\norder by month\n)\n\nselect\n    *,\n    round(num_add_to_cart/num_product_view * 100, 2) as add_to_cart_rate,\n    round(num_purchase/num_product_view * 100, 2) as purchase_rate\nfrom product_data;\n```\n** ✅ Results:** \n| month  | num_product_view | num_add_to_cart | num_purchase | add_to_cart_rate | purchase_rate |\n| ------ | ---------------- | --------------- | ------------ | ---------------- | ------------- |\n| 201701 | 25787            | 7342            | 2143         | 28.47            | 8.31          |\n| 201702 | 21489            | 7360            | 2060         | 34.25            | 9.59          |\n| 201703 | 23549            | 8782            | 2977         | 37.29            | 12.64         |\n\n**📝 Observation:** Conversion rates improve over time, with March showing the highest add-to-cart (37.29%) and purchase (12.64%) rates among the three months.\n## 🔎 Final Conclusion \u0026 Recommendations\n\n👉🏻 Based on the insights and findings above, we would recommend the **Ecommerce \u0026 Marketing Team** to consider the following:\n\n### 📌 Key Takeaways:\n\n✔️ **Replicate successful March strategies** across future campaigns, as this month showed consistent growth in visits, engagement, and conversions.  \n✔️ **Improve high-bounce traffic sources** such as YouTube and Facebook by optimizing ad content or landing pages to improve engagement.  \n✔️ **Introduce product bundles** that include “YouTube Men's Vintage Henley” and frequently co-purchased items (e.g., Google Sunglasses) to increase average order value.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnph1508%2Fsql_for_ecommerce_analyzing_sales_customer_behavior_in_bigquery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnph1508%2Fsql_for_ecommerce_analyzing_sales_customer_behavior_in_bigquery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnph1508%2Fsql_for_ecommerce_analyzing_sales_customer_behavior_in_bigquery/lists"}