็คผๅŒ…็ ๆŠฅ่กจ๏ผšๆ•ฐๆฎ้ฉฑๅŠจ่ฟ่ฅๅ†ณ็ญ–๏ผˆๆทฑๅบฆๆŠ€ๆœฏ็ฏ‡๏ผ‰

ๆœฌๆ–‡ๆ˜ฏ็คผๅŒ…็ ็ณปๅˆ—็š„็ฌฌ6็ฏ‡๏ผŒไนŸๆ˜ฏๆœ€ๅŽไธ€็ฏ‡ใ€‚ๅ‰ไบ”็ฏ‡ๆˆ‘ไปฌๅˆ†ๅˆซไป‹็ปไบ†็คผๅŒ…็ ็š„ๅŸบ็ก€ๆžถๆž„ใ€็”Ÿๆˆ็ฎ—ๆณ•ใ€ๆ‰น้‡็ฎก็†ใ€ๅ…‘ๆขไบ‹ๅŠกๅ’Œๅކๅฒ่ฟฝๆบฏใ€‚ไปŠๅคฉ๏ผŒๆˆ‘ไปฌๆฅ่Š่Šๆ•ดไธช็ณป็ปŸ็š„"็œผ็›"โ€”โ€”ๆŠฅ่กจ็ณป็ปŸ๏ผŒ็œ‹็œ‹ๅฆ‚ไฝ•้€š่ฟ‡ๆ•ฐๆฎ้ฉฑๅŠจ่ฟ่ฅๅ†ณ็ญ–ใ€‚


ไธ€ใ€็คผๅŒ…็ ๆ•ฐๆฎ็š„ไปทๅ€ผ

่ฟ่ฅๆดปๅŠจ็š„ๆ•ˆๆžœๅฆ‚ไฝ•๏ผŸ็Žฉๅฎถๅ–œๆฌขไป€ไนˆๅฅ–ๅŠฑ๏ผŸๆธ ้“ๆŠ•ๆ”พ็š„ROIๆ€Žๆ ท๏ผŸ

่ฟ™ไบ›้—ฎ้ข˜๏ผŒๅ…‰้ "ๆ„Ÿ่ง‰"ๆ˜ฏๅ›ž็ญ”ไธไบ†็š„ใ€‚

็คผๅŒ…็ ็ณป็ปŸ็š„็œŸๆญฃไปทๅ€ผ๏ผŒไธๅœจไบŽๅฎƒ่ƒฝๅ‘ๅ‡บๅคšๅฐ‘็คผๅŒ…๏ผŒ่€ŒๅœจไบŽๅฎƒ่ƒฝไธบ่ฟ่ฅๅ†ณ็ญ–ๆไพ›ไป€ไนˆๆ•ฐๆฎๆ”ฏๆ’‘ใ€‚ๆฏไธ€ๆฌกๅ…‘ๆขใ€ๆฏไธ€ไธช็ ็š„็”Ÿๆˆๅ’Œไฝฟ็”จ๏ผŒ้ƒฝๆ˜ฏไธ€้ข—ๆ•ฐๆฎ็็ ใ€‚ๆŠŠๅฎƒไปฌไธฒ่ตทๆฅ๏ผŒๅฐฑๆ˜ฏไธ€ๆกๅฎŒๆ•ด็š„่ฟ่ฅๆดžๅฏŸ้กน้“พใ€‚

ไผ ็ปŸ็š„่ฟ่ฅๅ†ณ็ญ–๏ผŒๅพ€ๅพ€ไพ่ต–็ป้ชŒ๏ผš"ๆˆ‘่ง‰ๅพ—่ฟ™ไธชๆดปๅŠจไผš็ซ"ใ€"ไธŠๆฌก็ฑปไผผ็š„ๆดปๅŠจๆ•ˆๆžœไธ้”™"ใ€‚ไฝ†็ป้ชŒๆœ‰ๅฑ€้™ๆ€งโ€”โ€”ๅธ‚ๅœบๅœจๅ˜๏ผŒ็Žฉๅฎถๅœจๅ˜๏ผŒไฝ ็š„็ป้ชŒๅฏ่ƒฝๅทฒ็ป่ฟ‡ๆ—ถไบ†ใ€‚

ๆ•ฐๆฎ้ฉฑๅŠจ็š„่ฟ่ฅ๏ผŒๆ˜ฏ่ฎฉๆ•ฐๅญ—่ฏด่ฏใ€‚ไธๆ˜ฏ"ๆˆ‘่ง‰ๅพ—"๏ผŒ่€Œๆ˜ฏ"ๆ•ฐๆฎๆ˜พ็คบ"ใ€‚่ฟ™ไธๆ˜ฏๅฆๅฎš็ป้ชŒ็š„ไปทๅ€ผ๏ผŒ่€Œๆ˜ฏ็”จๆ•ฐๆฎ้ชŒ่ฏ็ป้ชŒ๏ผŒ็”จๆ•ฐๆฎไฟฎๆญฃๅ่งใ€‚

ๆฏไธ€ๆฌกๆดปๅŠจ๏ผŒ้ƒฝๆ˜ฏไธ€ๆฌกๆ•ฐๆฎ็งฏ็ดฏใ€‚ไปŠๅนด็š„"ๆ˜ฅ่Š‚ๆดปๅŠจ"ๆ•ฐๆฎ๏ผŒๅฏไปฅๅ’ŒๅŽปๅนดๅฏนๆฏ”๏ผ›ไปŠๅนด็š„"618ๆดปๅŠจ"ๆ•ฐๆฎ๏ผŒๅฏไปฅๆŒ‡ๅฏผๆ˜Žๅนด็š„็ญ–็•ฅ่ง„ๅˆ’ใ€‚

ๆ•ฐๆฎ่ถŠ็งฏ็ดฏ๏ผŒไปทๅ€ผ่ถŠๅคงใ€‚ไธ€ไธช่ฟ่กŒไบ†ไธ‰ๅนด็š„็คผๅŒ…็ ็ณป็ปŸ๏ผŒๆฒ‰ๆท€ไธ‹ๆฅ็š„ไธๅชๆ˜ฏๅ‡ ็™พไธ‡ๆกๅ…‘ๆข่ฎฐๅฝ•๏ผŒ่€Œๆ˜ฏๅฏน็”จๆˆท่กŒไธบใ€ๅธ‚ๅœบ่ง„ๅพ‹็š„ๆทฑๅˆป็†่งฃใ€‚่ฟ™ไบ›็†่งฃ๏ผŒๆ˜ฏ็ซžไบ‰ๅฏนๆ‰‹็ŸญๆœŸๅ†…ๆ— ๆณ•ๅคๅˆถ็š„ๆŠคๅŸŽๆฒณใ€‚

็ฌฌไธ€ๅฑ‚๏ผš็œ‹ๆ•ฐๆฎใ€‚็Ÿฅ้“ๅ‘็”Ÿไบ†ไป€ไนˆ๏ผŒ่ฟ™ๆ˜ฏๆœ€ๅŸบ็ก€็š„ใ€‚ ็ฌฌไบŒๅฑ‚๏ผšๆ‡‚ๅŽŸๅ› ใ€‚็Ÿฅ้“ไธบไป€ไนˆๅ‘็”Ÿ๏ผŒ่ฟ™้œ€่ฆๅˆ†ๆž่ƒฝๅŠ›ใ€‚ ็ฌฌไธ‰ๅฑ‚๏ผš่ƒฝ้ข„ๆต‹ใ€‚็Ÿฅ้“ๅฐ†่ฆๅ‘็”Ÿไป€ไนˆ๏ผŒ่ฟ™้œ€่ฆๅปบๆจก่ƒฝๅŠ›ใ€‚

ๅคงๅคšๆ•ฐๅ›ข้˜Ÿๅœ็•™ๅœจ็ฌฌไธ€ๅฑ‚๏ผŒๅฐ‘ๆ•ฐๅ›ข้˜Ÿ่ƒฝๅˆฐ็ฌฌไบŒๅฑ‚๏ผŒ่ƒฝๅˆฐ็ฌฌไธ‰ๅฑ‚็š„ๅ‡คๆฏ›้บŸ่ง’ใ€‚ๆŠฅ่กจ็ณป็ปŸ็š„็›ฎๆ ‡๏ผŒๆ˜ฏๅธฎๅŠฉๅ›ข้˜ŸไปŽ็ฌฌไธ€ๅฑ‚่ตฐๅ‘็ฌฌไบŒๅฑ‚๏ผŒๆœ€็ปˆ่พพๅˆฐ็ฌฌไธ‰ๅฑ‚ใ€‚


ไบŒใ€ๆ•ฐๆฎไป“ๅบ“ๆžถๆž„่ฎพ่ฎก

ๅœจๆทฑๅ…ฅๆŒ‡ๆ ‡ๅ’ŒๆŠฅ่กจไน‹ๅ‰๏ผŒๆˆ‘ไปฌ้œ€่ฆๅ…ˆ็†่งฃๆ•ฐๆฎๆ˜ฏๅฆ‚ไฝ•่ขซ็ป„็ป‡ๅ’Œๅญ˜ๅ‚จ็š„ใ€‚่ฟ™ๅฐฑๅƒๅปบๆˆฟๅญ๏ผŒๅ…ˆ่ฆๆ‰“ๅฅฝๅœฐๅŸบใ€‚

2.1 ๆ•ฐๆฎๅˆ†ๅฑ‚ๆžถๆž„

็Žฐไปฃๆ•ฐๆฎไป“ๅบ“้€šๅธธ้‡‡็”จๅˆ†ๅฑ‚ๆžถๆž„๏ผŒๆŠŠๆ•ฐๆฎๆŒ‰็…งๅค„็†้˜ถๆฎตๅˆ†ๆˆไธๅŒ็š„ๅฑ‚ๆฌก๏ผš

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      ADS (ๅบ”็”จๆ•ฐๆฎๅฑ‚)                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”‚
โ”‚   โ”‚ ่ฟ่ฅๆŠฅ่กจ โ”‚  โ”‚ ๅฎžๆ—ถ็›‘ๆŽง โ”‚  โ”‚ ๆ•ฐๆฎAPI  โ”‚  โ”‚ ๅฏผๅ‡บๆœๅŠก โ”‚        โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                      DWS (ๆฑ‡ๆ€ปๆ•ฐๆฎๅฑ‚)                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚   โ”‚ ๆดปๅŠจๆ—ฅๆฑ‡ๆ€ป่กจ โ”‚  โ”‚ ๆธ ้“ๆ—ฅๆฑ‡ๆ€ป่กจ โ”‚  โ”‚ ็”จๆˆทๆ—ฅๆฑ‡ๆ€ป่กจ โ”‚         โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                      DWD (ๆ˜Ž็ป†ๆ•ฐๆฎๅฑ‚)                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚   โ”‚ ๅ…‘ๆขๆ˜Ž็ป†ๅฎฝ่กจ โ”‚  โ”‚ ็ ็”Ÿๅ‘ฝๅ‘จๆœŸ่กจ โ”‚  โ”‚ ็”จๆˆท่กŒไธบ่กจ  โ”‚         โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                      ODS (ๅŽŸๅง‹ๆ•ฐๆฎๅฑ‚)                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚   โ”‚ ๅ…‘ๆขๆตๆฐด่กจ  โ”‚  โ”‚ ็ ็”Ÿๆˆ่ฎฐๅฝ•่กจ โ”‚  โ”‚ ็”จๆˆทๅŸบ็ก€่กจ  โ”‚         โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฟ™ไธ€ๅฑ‚็›ดๆŽฅๅŒๆญฅไธšๅŠกๆ•ฐๆฎๅบ“็š„ๅŽŸๅง‹ๆ•ฐๆฎ๏ผŒไฟๆŒๅ’ŒไธšๅŠก็ณป็ปŸไธ€่‡ด็š„็ป“ๆž„ใ€‚ๅฏไปฅๆŠŠๅฎƒๆƒณ่ฑกๆˆไธ€ไธช"ๆ•ฐๆฎๅค‡ไปฝไป“ๅบ“"๏ผŒไธๅšไปปไฝ•ๅŠ ๅทฅๅค„็†ใ€‚

-- ODSๅฑ‚๏ผšๅ…‘ๆขๆตๆฐด่กจ๏ผˆๅŽŸๅง‹ๆ•ฐๆฎ๏ผ‰
CREATE TABLE ods_gift_code_redeem_log (
    id              BIGINT PRIMARY KEY,
    code_id         BIGINT NOT NULL COMMENT '็คผๅŒ…็ ID',
    code            VARCHAR(32) NOT NULL COMMENT '็คผๅŒ…็ ',
    user_id         BIGINT NOT NULL COMMENT '็”จๆˆทID',
    activity_id     BIGINT NOT NULL COMMENT 'ๆดปๅŠจID',
    channel_id      BIGINT COMMENT 'ๆธ ้“ID',
    reward_id       BIGINT NOT NULL COMMENT 'ๅฅ–ๅŠฑ้…็ฝฎID',
    redeem_time     DATETIME NOT NULL COMMENT 'ๅ…‘ๆขๆ—ถ้—ด',
    redeem_ip       VARCHAR(45) COMMENT 'ๅ…‘ๆขIP',
    device_id       VARCHAR(64) COMMENT '่ฎพๅค‡ID',
    status          TINYINT NOT NULL COMMENT '็Šถๆ€๏ผš1ๆˆๅŠŸ 2ๅคฑ่ดฅ',
    fail_reason     VARCHAR(255) COMMENT 'ๅคฑ่ดฅๅŽŸๅ› ',
    created_at      DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_code_id (code_id),
    INDEX idx_user_id (user_id),
    INDEX idx_activity_id (activity_id),
    INDEX idx_redeem_time (redeem_time)
) COMMENT 'ๅ…‘ๆขๆตๆฐดๅŽŸๅง‹่กจ';

่ฟ™ไธ€ๅฑ‚ๅฏนๅŽŸๅง‹ๆ•ฐๆฎ่ฟ›่กŒๆธ…ๆด—ใ€่ฝฌๆขๅ’Œๆ•ดๅˆ๏ผŒๅฝขๆˆๅฎฝ่กจใ€‚ๅฎฝ่กจ็š„ๆ„ๆ€ๆ˜ฏๆŠŠๅคšไธช็›ธๅ…ณ่กจ็š„ๆ•ฐๆฎๅˆๅนถๅˆฐไธ€่ตท๏ผŒๆ–นไพฟๅŽ็ปญๅˆ†ๆžใ€‚

-- DWDๅฑ‚๏ผšๅ…‘ๆขๆ˜Ž็ป†ๅฎฝ่กจ๏ผˆ็ป่ฟ‡ๆธ…ๆด—ๅ’Œๅ…ณ่”๏ผ‰
CREATE TABLE dwd_gift_code_redeem_detail (
    -- ๅ…‘ๆขๅŸบ็ก€ไฟกๆฏ
    redeem_id           BIGINT PRIMARY KEY,
    code_id             BIGINT NOT NULL,
    code                VARCHAR(32) NOT NULL,
    user_id             BIGINT NOT NULL,
    
    -- ๆดปๅŠจ็ปดๅบฆ
    activity_id         BIGINT NOT NULL,
    activity_name       VARCHAR(128) COMMENT 'ๆดปๅŠจๅ็งฐ',
    activity_type       VARCHAR(32) COMMENT 'ๆดปๅŠจ็ฑปๅž‹๏ผšNEW_USER/DAILY/CHANNEL',
    activity_start_time DATETIME COMMENT 'ๆดปๅŠจๅผ€ๅง‹ๆ—ถ้—ด',
    activity_end_time   DATETIME COMMENT 'ๆดปๅŠจ็ป“ๆŸๆ—ถ้—ด',
    
    -- ๆธ ้“็ปดๅบฆ
    channel_id          BIGINT,
    channel_name        VARCHAR(64) COMMENT 'ๆธ ้“ๅ็งฐ',
    channel_type        VARCHAR(32) COMMENT 'ๆธ ้“็ฑปๅž‹๏ผšSOCIAL/ADS/PARTNER',
    
    -- ๅฅ–ๅŠฑ็ปดๅบฆ
    reward_id           BIGINT NOT NULL,
    reward_name         VARCHAR(128) COMMENT 'ๅฅ–ๅŠฑๅ็งฐ',
    reward_type         VARCHAR(32) COMMENT 'ๅฅ–ๅŠฑ็ฑปๅž‹๏ผšGOLD/ITEM/SKIN',
    reward_value        DECIMAL(18,2) COMMENT 'ๅฅ–ๅŠฑไปทๅ€ผ๏ผˆ็ญ‰ไปทไบบๆฐ‘ๅธ๏ผ‰',
    
    -- ็”จๆˆท็ปดๅบฆ
    user_register_time  DATETIME COMMENT '็”จๆˆทๆณจๅ†Œๆ—ถ้—ด',
    user_level          INT COMMENT '็”จๆˆท็ญ‰็บง',
    user_vip_level      INT COMMENT 'VIP็ญ‰็บง',
    is_new_user         TINYINT COMMENT 'ๆ˜ฏๅฆๆ–ฐ็”จๆˆท๏ผˆๆณจๅ†Œ7ๅคฉๅ†…๏ผ‰',
    user_total_recharge DECIMAL(18,2) COMMENT 'ๅކๅฒๅ……ๅ€ผๆ€ป้ข',
    
    -- ๆ—ถ้—ด็ปดๅบฆ
    redeem_time         DATETIME NOT NULL,
    redeem_date         DATE COMMENT 'ๅ…‘ๆขๆ—ฅๆœŸ',
    redeem_hour         TINYINT COMMENT 'ๅ…‘ๆขๅฐๆ—ถ๏ผˆ0-23๏ผ‰',
    day_of_week         TINYINT COMMENT 'ๆ˜ŸๆœŸๅ‡ ๏ผˆ1-7๏ผ‰',
    is_weekend          TINYINT COMMENT 'ๆ˜ฏๅฆๅ‘จๆœซ',
    
    -- ่ฎพๅค‡ๅ’Œไฝ็ฝฎ
    redeem_ip           VARCHAR(45),
    device_id           VARCHAR(64),
    device_type         VARCHAR(32) COMMENT '่ฎพๅค‡็ฑปๅž‹๏ผšiOS/Android',
    province            VARCHAR(32) COMMENT '็œไปฝ',
    city                VARCHAR(32) COMMENT 'ๅŸŽๅธ‚',
    
    -- ๅ…‘ๆข็ป“ๆžœ
    status              TINYINT NOT NULL,
    fail_reason         VARCHAR(255),
    
    -- ETLๅญ—ๆฎต
    etl_time            DATETIME DEFAULT CURRENT_TIMESTAMP,
    
    INDEX idx_activity_date (activity_id, redeem_date),
    INDEX idx_channel_date (channel_id, redeem_date),
    INDEX idx_user_date (user_id, redeem_date),
    INDEX idx_redeem_date (redeem_date)
) COMMENT 'ๅ…‘ๆขๆ˜Ž็ป†ๅฎฝ่กจ';

่ฟ™ไธ€ๅฑ‚ๅฏนๆ˜Ž็ป†ๆ•ฐๆฎ่ฟ›่กŒ่šๅˆๆฑ‡ๆ€ป๏ผŒๆŒ‰็…งไธๅŒ็š„ๅˆ†ๆž็ปดๅบฆ้ข„ๅ…ˆ่ฎก็ฎ—ๅฅฝๆŒ‡ๆ ‡ใ€‚่ฟ™ๆ ทๆŸฅ่ฏขๆŠฅ่กจๆ—ถๅฐฑไธ้œ€่ฆๆฏๆฌก้ƒฝๆ‰ซๆๅคง้‡ๆ˜Ž็ป†ๆ•ฐๆฎ๏ผŒๆ€ง่ƒฝไผšๅฅฝๅพˆๅคšใ€‚

-- DWSๅฑ‚๏ผšๆดปๅŠจๆ—ฅๆฑ‡ๆ€ป่กจ
CREATE TABLE dws_activity_daily_summary (
    activity_id         BIGINT NOT NULL,
    stat_date           DATE NOT NULL,
    
    -- ็ ็š„็ปŸ่ฎก
    total_codes         INT COMMENT '็ดฏ่ฎก็”Ÿๆˆ็ ๆ•ฐ',
    available_codes     INT COMMENT 'ๅฏ็”จ็ ๆ•ฐ',
    redeemed_codes      INT COMMENT 'ๅทฒๅ…‘ๆข็ ๆ•ฐ',
    code_usage_rate     DECIMAL(5,2) COMMENT '็ ไฝฟ็”จ็އ๏ผˆ%๏ผ‰',
    
    -- ๅ…‘ๆข็ปŸ่ฎก
    total_redeems       INT COMMENT 'ๆ€ปๅ…‘ๆขๆฌกๆ•ฐ',
    success_redeems     INT COMMENT 'ๆˆๅŠŸๅ…‘ๆขๆฌกๆ•ฐ',
    fail_redeems        INT COMMENT 'ๅคฑ่ดฅๅ…‘ๆขๆฌกๆ•ฐ',
    redeem_success_rate DECIMAL(5,2) COMMENT 'ๅ…‘ๆขๆˆๅŠŸ็އ๏ผˆ%๏ผ‰',
    
    -- ็”จๆˆท็ปŸ่ฎก
    unique_users        INT COMMENT '็‹ฌ็ซ‹ๅ…‘ๆข็”จๆˆทๆ•ฐ',
    new_users           INT COMMENT 'ๆ–ฐ็”จๆˆทๆ•ฐ',
    old_users           INT COMMENT '่€็”จๆˆทๆ•ฐ',
    new_user_ratio      DECIMAL(5,2) COMMENT 'ๆ–ฐ็”จๆˆทๅ ๆฏ”๏ผˆ%๏ผ‰',
    avg_redeems_per_user DECIMAL(5,2) COMMENT 'ไบบๅ‡ๅ…‘ๆขๆฌกๆ•ฐ',
    
    -- ๆ—ถ้—ด็ปŸ่ฎก
    peak_hour           TINYINT COMMENT 'ๅณฐๅ€ผๅ…‘ๆขๅฐๆ—ถ',
    peak_hour_redeems   INT COMMENT 'ๅณฐๅ€ผๅฐๆ—ถๅ…‘ๆข้‡',
    avg_redeem_interval INT COMMENT 'ๅนณๅ‡ๅ…‘ๆข้—ด้š”๏ผˆ็ง’๏ผ‰',
    
    -- ไปทๅ€ผ็ปŸ่ฎก
    total_reward_value  DECIMAL(18,2) COMMENT 'ๅ‘ๆ”พๅฅ–ๅŠฑๆ€ปไปทๅ€ผ',
    avg_reward_value    DECIMAL(18,2) COMMENT 'ๅนณๅ‡ๅฅ–ๅŠฑไปทๅ€ผ',
    
    -- ๅŒ็Žฏๆฏ”
    redeem_dod          DECIMAL(5,2) COMMENT 'ๅ…‘ๆข้‡ๆ—ฅ็Žฏๆฏ”๏ผˆ%๏ผ‰',
    redeem_wow          DECIMAL(5,2) COMMENT 'ๅ…‘ๆข้‡ๅ‘จๅŒๆฏ”๏ผˆ%๏ผ‰',
    
    -- ETLๅญ—ๆฎต
    etl_time            DATETIME DEFAULT CURRENT_TIMESTAMP,
    
    PRIMARY KEY (activity_id, stat_date),
    INDEX idx_stat_date (stat_date)
) COMMENT 'ๆดปๅŠจๆ—ฅๆฑ‡ๆ€ป่กจ';

่ฟ™ไธ€ๅฑ‚ๆ˜ฏ็›ดๆŽฅ้ขๅ‘ๆŠฅ่กจๅ’ŒAPI็š„ๆ•ฐๆฎๅฑ‚๏ผŒๆ•ฐๆฎๆ ผๅผๅฎŒๅ…จๆŒ‰็…งๅ‰็ซฏๅฑ•็คบ้œ€ๆฑ‚ๆฅ่ฎพ่ฎกใ€‚

-- ADSๅฑ‚๏ผšๅฎžๆ—ถ็›‘ๆŽงๆŒ‡ๆ ‡่กจ
CREATE TABLE ads_realtime_monitor (
    metric_name         VARCHAR(64) PRIMARY KEY,
    metric_value        DECIMAL(18,2),
    metric_unit         VARCHAR(16),
    compare_value       DECIMAL(18,2) COMMENT 'ๅฏนๆฏ”ๅ€ผ๏ผˆๆ˜จๆ—ฅๅŒๆœŸ/ไธŠๅ‘จๅŒๆœŸ๏ผ‰',
    change_rate         DECIMAL(5,2) COMMENT 'ๅ˜ๅŒ–็އ๏ผˆ%๏ผ‰',
    trend               VARCHAR(8) COMMENT '่ถ‹ๅŠฟ๏ผšUP/DOWN/FLAT',
    status              VARCHAR(16) COMMENT '็Šถๆ€๏ผšNORMAL/WARNING/ALERT',
    update_time         DATETIME,
    
    INDEX idx_update_time (update_time)
) COMMENT 'ๅฎžๆ—ถ็›‘ๆŽงๆŒ‡ๆ ‡่กจ';

2.2 ๆ•ฐๆฎๆต่ฝฌ็ฎก้“

ๆ•ฐๆฎไปŽไธšๅŠก็ณป็ปŸๆตๅ‘ๆŠฅ่กจ็ณป็ปŸ๏ผŒ้œ€่ฆ็ป่ฟ‡ไธ€ไธชETL๏ผˆExtract-Transform-Load๏ผ‰็ฎก้“๏ผš

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   ไธšๅŠกๆ•ฐๆฎๅบ“   โ”‚โ”€โ”€โ”€โ–ถโ”‚   ๆถˆๆฏ้˜Ÿๅˆ—    โ”‚โ”€โ”€โ”€โ–ถโ”‚  ๆตๅค„็†ๅผ•ๆ“Ž   โ”‚โ”€โ”€โ”€โ–ถโ”‚   ๅฎžๆ—ถๆ•ฐไป“    โ”‚
โ”‚   (MySQL)    โ”‚    โ”‚  (Kafka)     โ”‚    โ”‚ (Flink)     โ”‚    โ”‚  (ClickHouse) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚                                                           โ”‚
       โ”‚                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                       โ”‚
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚   ๆ‰นๅค„็†ๅผ•ๆ“Ž  โ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                            โ”‚   (Spark)    โ”‚
                            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                   โ”‚
                                   โ–ผ
                            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                            โ”‚   ็ฆป็บฟๆ•ฐไป“    โ”‚
                            โ”‚  (Hive/Doris) โ”‚
                            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

2.3 ๆ•ฐๆฎ่ดจ้‡ไฟ้šœ

ๆ•ฐๆฎ่ดจ้‡ๆ˜ฏๆŠฅ่กจ็ณป็ปŸ็š„็”Ÿๅ‘ฝ็บฟใ€‚ๅžƒๅœพ่ฟ›๏ผŒๅžƒๅœพๅ‡บโ€”โ€”ๅฆ‚ๆžœๆบๆ•ฐๆฎๆœ‰้—ฎ้ข˜๏ผŒๅ†ๆผ‚ไบฎ็š„ๆŠฅ่กจไนŸๆ˜ฏ่ฏฏๅฏผใ€‚

-- ๆ•ฐๆฎๅฎŒๆ•ดๆ€งๆฃ€ๆŸฅ๏ผšๆ˜ฏๅฆๆœ‰ไธขๅคฑๆ•ฐๆฎ
SELECT 
    DATE(redeem_time) as stat_date,
    COUNT(*) as record_count,
    COUNT(DISTINCT user_id) as unique_users
FROM ods_gift_code_redeem_log
WHERE redeem_time >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
GROUP BY DATE(redeem_time)
HAVING record_count < 100 OR unique_users < 10;  -- ้˜ˆๅ€ผๅฏๆ นๆฎไธšๅŠก่ฐƒๆ•ด

-- ๆ•ฐๆฎไธ€่‡ดๆ€งๆฃ€ๆŸฅ๏ผšๅ…‘ๆข่ฎฐๅฝ•ๅ’Œ็ ็š„็Šถๆ€ๆ˜ฏๅฆไธ€่‡ด
SELECT 
    r.code_id,
    r.user_id,
    r.redeem_time,
    c.status as code_status,
    CASE WHEN c.status = 1 AND r.status = 1 THEN 'OK'
         WHEN c.status = 0 AND r.status = 2 THEN 'OK'
         ELSE 'INCONSISTENT' END as check_result
FROM ods_gift_code_redeem_log r
LEFT JOIN gift_code c ON r.code_id = c.id
WHERE r.redeem_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
HAVING check_result = 'INCONSISTENT';

-- ๆ•ฐๆฎๅŠๆ—ถๆ€งๆฃ€ๆŸฅ๏ผšETLๆ˜ฏๅฆๆŒ‰ๆ—ถๅฎŒๆˆ
SELECT 
    table_name,
    max_etl_time,
    TIMESTAMPDIFF(MINUTE, max_etl_time, NOW()) as delay_minutes
FROM (
    SELECT 'dwd_gift_code_redeem_detail' as table_name,
           MAX(etl_time) as max_etl_time
    FROM dwd_gift_code_redeem_detail
    UNION ALL
    SELECT 'dws_activity_daily_summary' as table_name,
           MAX(etl_time) as max_etl_time
    FROM dws_activity_daily_summary
) t
HAVING delay_minutes > 120;  -- ่ถ…่ฟ‡2ๅฐๆ—ถๆŠฅ่ญฆ

ไธ‰ใ€ๆ ธๅฟƒๆ•ฐๆฎๆŒ‡ๆ ‡

่ฆๅšๅฅฝๆŠฅ่กจ๏ผŒ้ฆ–ๅ…ˆ่ฆๆ˜Ž็กฎ๏ผšๅ“ชไบ›ๆŒ‡ๆ ‡ๆ˜ฏๅ€ผๅพ—ๅ…ณๆณจ็š„๏ผŸ

3.1 ๅ…‘ๆข็ฑปๆŒ‡ๆ ‡

่ฟ™ๆ˜ฏๆœ€ๆ ธๅฟƒ็š„ๆŒ‡ๆ ‡ใ€‚ๅ…‘ๆข็އไฝŽ๏ผŒ่ฏดๆ˜ŽๆดปๅŠจๅธๅผ•ๅŠ›ไธ่ถณ๏ผŒๆˆ–่€…ๆŠ•ๆ”พๆธ ้“ไธๅฏนใ€‚ๅ…‘ๆข็އ่ฟ‡้ซ˜๏ผˆๆฏ”ๅฆ‚่ถ…่ฟ‡100%๏ผ‰๏ผŒๅˆ™้œ€่ฆ่ญฆๆƒ•โ€”โ€”ๅฏ่ƒฝๆ˜ฏ็ ่ขซๆณ„้œฒๆˆ–ๆปฅ็”จไบ†ใ€‚

ไฝ†ๅ…‘ๆข็އไธๆ˜ฏ่ถŠ้ซ˜่ถŠๅฅฝใ€‚100%็š„ๅ…‘ๆข็އ๏ผŒๆ„ๅ‘ณ็€ๆฒกๆœ‰ๅ†—ไฝ™๏ผŒๆฒกๆœ‰ๅฎน้”™็ฉบ้—ดใ€‚ๅฆ‚ๆžœๆธ ้“้œ€่ฆ่ฟฝๅŠ ๆŠ•ๆ”พ๏ผŒๆ‰‹ไธŠๅทฒ็ปๆฒกๆœ‰็ ไบ†ใ€‚ไธ€่ˆฌๅปบ่ฎฎ้ข„็•™10-20%็š„ไฝ™้‡ใ€‚

-- ่ฎก็ฎ—ๆดปๅŠจๅ…‘ๆข็އ
SELECT 
    a.activity_id,
    a.activity_name,
    COUNT(DISTINCT gc.id) as total_codes,
    COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) as redeemed_codes,
    ROUND(COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) * 100.0 / 
          NULLIF(COUNT(DISTINCT gc.id), 0), 2) as redeem_rate_pct,
    
    -- ๆœ‰ๆ•ˆๅ…‘ๆข็އ๏ผˆๅช่ฎก็ฎ—ๆœช่ฟ‡ๆœŸใ€ๆœชๅ–ๆถˆ็š„็ ๏ผ‰
    COUNT(DISTINCT CASE WHEN gc.status = 1 AND gc.expire_time > NOW() THEN gc.id END) as valid_redeemed,
    ROUND(COUNT(DISTINCT CASE WHEN gc.status = 1 AND gc.expire_time > NOW() THEN gc.id END) * 100.0 / 
          NULLIF(COUNT(DISTINCT CASE WHEN gc.expire_time > NOW() AND gc.cancelled_at IS NULL THEN gc.id END), 0), 2) 
          as valid_redeem_rate_pct
FROM activity a
LEFT JOIN gift_code gc ON a.id = gc.activity_id
WHERE a.start_time >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
GROUP BY a.activity_id, a.activity_name
ORDER BY redeem_rate_pct DESC;

10000ไธช็ ๏ผŒๆ˜ฏ1ๅฐๆ—ถๅ†…่ขซๆŠขๅ…‰๏ผŒ่ฟ˜ๆ˜ฏ1ไธชๆœˆ้ƒฝๆฒกๅ‘ๅฎŒ๏ผŸๅ…‘ๆข้€Ÿๅบฆๅๆ˜ ไบ†ๆดปๅŠจ็š„็ƒญๅบฆๅ’Œ็ดง่ฟซๆ„Ÿใ€‚

-- ่ฎก็ฎ—ๅ…‘ๆข้€ŸๅบฆๆŒ‡ๆ ‡๏ผˆT50/T90/T99๏ผ‰
WITH redeem_timeline AS (
    SELECT 
        gc.activity_id,
        gc.id as code_id,
        r.redeem_time,
        a.start_time as activity_start,
        ROW_NUMBER() OVER (PARTITION BY gc.activity_id ORDER BY r.redeem_time) as redeem_rank,
        COUNT(*) OVER (PARTITION BY gc.activity_id) as total_redeemed
    FROM gift_code gc
    INNER JOIN gift_code_redeem_log r ON gc.id = r.code_id AND r.status = 1
    INNER JOIN activity a ON gc.activity_id = a.id
    WHERE gc.status = 1
),
percentiles AS (
    SELECT 
        activity_id,
        MIN(redeem_time) as first_redeem,
        MAX(redeem_time) as last_redeem,
        MAX(CASE WHEN redeem_rank <= total_redeemed * 0.5 THEN redeem_time END) as t50_time,
        MAX(CASE WHEN redeem_rank <= total_redeemed * 0.9 THEN redeem_time END) as t90_time,
        MAX(CASE WHEN redeem_rank <= total_redeemed * 0.99 THEN redeem_time END) as t99_time,
        MAX(activity_start) as activity_start,
        MAX(total_redeemed) as total_redeemed
    FROM redeem_timeline
    GROUP BY activity_id
)
SELECT 
    activity_id,
    total_redeemed,
    TIMESTAMPDIFF(MINUTE, activity_start, first_redeem) as minutes_to_first,
    TIMESTAMPDIFF(MINUTE, activity_start, t50_time) as minutes_to_t50,
    TIMESTAMPDIFF(MINUTE, activity_start, t90_time) as minutes_to_t90,
    TIMESTAMPDIFF(MINUTE, activity_start, t99_time) as minutes_to_t99,
    TIMESTAMPDIFF(HOUR, activity_start, last_redeem) as hours_total
FROM percentiles
ORDER BY total_redeemed DESC;

่ฟ™ไธชๆŒ‡ๆ ‡ๅธฎๅŠฉ่ฏ„ไผฐ็ณป็ปŸ็š„ๆ‰ฟ่ฝฝ่ƒฝๅŠ›ใ€‚ๅฆ‚ๆžœๅณฐๅ€ผๅ…‘ๆข้‡่ฟœ่ถ…็ณป็ปŸ่ฎพ่ฎกๅฎน้‡๏ผŒไธ‹ๆฌกๆดปๅŠจๅ‰ๅฐฑ้œ€่ฆๆ‰ฉๅฎนใ€‚

-- ่ฎก็ฎ—ไธๅŒๆ—ถ้—ด็ฒ’ๅบฆ็š„ๅณฐๅ€ผๅ…‘ๆข้‡
SELECT 
    activity_id,
    redeem_date,
    -- ๅˆ†้’Ÿ็บงๅณฐๅ€ผ
    MAX(minute_redeems) as peak_minute_redeems,
    -- ๅฐๆ—ถ็บงๅณฐๅ€ผ
    MAX(hour_redeems) as peak_hour_redeems,
    -- ๅณฐๅ€ผๅ‘็”Ÿๆ—ถ้—ด
    SUBSTRING_INDEX(GROUP_CONCAT(peak_minute ORDER BY minute_redeems DESC), ',', 1) as peak_minute_time,
    SUBSTRING_INDEX(GROUP_CONCAT(peak_hour ORDER BY hour_redeems DESC), ',', 1) as peak_hour_time
FROM (
    SELECT 
        activity_id,
        DATE(redeem_time) as redeem_date,
        DATE_FORMAT(redeem_time, '%Y-%m-%d %H:%i') as minute_key,
        DATE_FORMAT(redeem_time, '%Y-%m-%d %H') as hour_key,
        COUNT(*) as minute_redeems,
        0 as hour_redeems,
        DATE_FORMAT(redeem_time, '%H:%i') as peak_minute,
        '' as peak_hour
    FROM dwd_gift_code_redeem_detail
    WHERE status = 1
    GROUP BY activity_id, DATE(redeem_time), DATE_FORMAT(redeem_time, '%Y-%m-%d %H:%i')
    
    UNION ALL
    
    SELECT 
        activity_id,
        DATE(redeem_time) as redeem_date,
        '' as minute_key,
        DATE_FORMAT(redeem_time, '%Y-%m-%d %H') as hour_key,
        0 as minute_redeems,
        COUNT(*) as hour_redeems,
        '' as peak_minute,
        DATE_FORMAT(redeem_time, '%H') as peak_hour
    FROM dwd_gift_code_redeem_detail
    WHERE status = 1
    GROUP BY activity_id, DATE(redeem_time), DATE_FORMAT(redeem_time, '%Y-%m-%d %H')
) t
GROUP BY activity_id, redeem_date
ORDER BY peak_minute_redeems DESC;

3.2 ็”จๆˆท็ฑปๆŒ‡ๆ ‡

ไธ€ไธช็”จๆˆทๅ…‘ๆข10ๆฌก๏ผŒๅ’Œ10ไธช็”จๆˆทๅ„ๅ…‘ๆข1ๆฌก๏ผŒๆ„ไน‰ๅฎŒๅ…จไธๅŒใ€‚ๅ‰่€…ๅฏ่ƒฝๆ˜ฏๅˆท็ ๏ผŒๅŽ่€…ๆ‰ๆ˜ฏ็œŸๆญฃ็š„็”จๆˆท่งฆ่พพใ€‚

-- ็”จๆˆทๅ…‘ๆข่กŒไธบๅˆ†ๆž
SELECT 
    activity_id,
    activity_name,
    -- ็”จๆˆท็ปŸ่ฎก
    COUNT(DISTINCT user_id) as unique_users,
    COUNT(*) as total_redeems,
    ROUND(COUNT(*) * 1.0 / COUNT(DISTINCT user_id), 2) as avg_redeems_per_user,
    
    -- ๆ–ฐ่€็”จๆˆทๅˆ†ๅธƒ
    COUNT(DISTINCT CASE WHEN is_new_user = 1 THEN user_id END) as new_users,
    COUNT(DISTINCT CASE WHEN is_new_user = 0 THEN user_id END) as old_users,
    ROUND(COUNT(DISTINCT CASE WHEN is_new_user = 1 THEN user_id END) * 100.0 / 
          COUNT(DISTINCT user_id), 2) as new_user_ratio,
    
    -- ๅ…‘ๆขๆฌกๆ•ฐๅˆ†ๅธƒ
    COUNT(CASE WHEN redeem_cnt = 1 THEN 1 END) as single_redeem_users,
    COUNT(CASE WHEN redeem_cnt BETWEEN 2 AND 5 THEN 1 END) as normal_multi_users,
    COUNT(CASE WHEN redeem_cnt > 5 THEN 1 END) as heavy_users
FROM (
    SELECT 
        d.activity_id,
        d.activity_name,
        d.user_id,
        d.is_new_user,
        COUNT(*) as redeem_cnt
    FROM dwd_gift_code_redeem_detail d
    WHERE d.status = 1
      AND d.redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY d.activity_id, d.activity_name, d.user_id, d.is_new_user
) user_redeems
GROUP BY activity_id, activity_name
ORDER BY unique_users DESC;

็”จๆˆทๅ…‘ๆขไบ†็คผๅŒ…๏ผŒ็„ถๅŽๅ‘ข๏ผŸๆ˜ฏๆ‹ฟไบ†ๅฅ–ๅŠฑๅฐฑ่ท‘๏ผŒ่ฟ˜ๆ˜ฏ็•™ไธ‹ๆฅ็ปง็ปญ็Žฉ๏ผŸ่ฟ™ไธชๆŒ‡ๆ ‡่กก้‡็š„ๆ˜ฏๆดปๅŠจ็š„้•ฟๆœŸไปทๅ€ผใ€‚

-- ็”จๆˆท็•™ๅญ˜ๅˆ†ๆž๏ผˆๅ…‘ๆขๅŽ7/14/30ๅคฉ็•™ๅญ˜๏ผ‰
WITH redeem_users AS (
    SELECT DISTINCT
        user_id,
        MIN(redeem_date) as first_redeem_date
    FROM dwd_gift_code_redeem_detail
    WHERE status = 1
      AND redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY)
    GROUP BY user_id
),
retention_check AS (
    SELECT 
        r.user_id,
        r.first_redeem_date,
        -- ๆฃ€ๆŸฅ็”จๆˆทๅœจๅ„็•™ๅญ˜ๆ—ฅๆ˜ฏๅฆๆดป่ทƒ
        MAX(CASE WHEN DATE_ADD(r.first_redeem_date, INTERVAL 1 DAY) = u.active_date THEN 1 END) as day1_active,
        MAX(CASE WHEN DATE_ADD(r.first_redeem_date, INTERVAL 7 DAY) = u.active_date THEN 1 END) as day7_active,
        MAX(CASE WHEN DATE_ADD(r.first_redeem_date, INTERVAL 14 DAY) = u.active_date THEN 1 END) as day14_active,
        MAX(CASE WHEN DATE_ADD(r.first_redeem_date, INTERVAL 30 DAY) = u.active_date THEN 1 END) as day30_active
    FROM redeem_users r
    LEFT JOIN user_daily_active u ON r.user_id = u.user_id
    WHERE u.active_date BETWEEN r.first_redeem_date AND DATE_ADD(r.first_redeem_date, INTERVAL 30 DAY)
    GROUP BY r.user_id, r.first_redeem_date
)
SELECT 
    first_redeem_date,
    COUNT(*) as total_users,
    SUM(IFNULL(day1_active, 0)) as day1_retained,
    SUM(IFNULL(day7_active, 0)) as day7_retained,
    SUM(IFNULL(day14_active, 0)) as day14_retained,
    SUM(IFNULL(day30_active, 0)) as day30_retained,
    ROUND(SUM(IFNULL(day1_active, 0)) * 100.0 / COUNT(*), 2) as day1_retention_pct,
    ROUND(SUM(IFNULL(day7_active, 0)) * 100.0 / COUNT(*), 2) as day7_retention_pct,
    ROUND(SUM(IFNULL(day14_active, 0)) * 100.0 / COUNT(*), 2) as day14_retention_pct,
    ROUND(SUM(IFNULL(day30_active, 0)) * 100.0 / COUNT(*), 2) as day30_retention_pct
FROM retention_check
GROUP BY first_redeem_date
ORDER BY first_redeem_date DESC;

3.3 ๆธ ้“็ฑปๆŒ‡ๆ ‡

ไธๅŒๆธ ้“็š„็”จๆˆท่ดจ้‡ๅทฎๅผ‚ๅพˆๅคงใ€‚้€š่ฟ‡ๅฏนๆฏ”ๅ„ๆธ ้“็š„ๅ…‘ๆข็އใ€ROIๅ’Œ็•™ๅญ˜๏ผŒๅฏไปฅไผ˜ๅŒ–ๆŠ•ๆ”พ็ญ–็•ฅใ€‚

-- ๆธ ้“็ปผๅˆๆ•ˆๆžœๅˆ†ๆž
SELECT 
    c.channel_id,
    c.channel_name,
    c.channel_type,
    
    -- ๆŠ•ๆ”พ็ปŸ่ฎก
    COUNT(DISTINCT gc.id) as total_codes,
    SUM(gc.cost) as total_cost,
    
    -- ๅ…‘ๆข็ปŸ่ฎก
    COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) as redeemed_codes,
    ROUND(COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) * 100.0 / 
          NULLIF(COUNT(DISTINCT gc.id), 0), 2) as redeem_rate,
    
    -- ็”จๆˆท็ปŸ่ฎก
    COUNT(DISTINCT r.user_id) as unique_users,
    COUNT(DISTINCT CASE WHEN d.is_new_user = 1 THEN r.user_id END) as new_users,
    ROUND(COUNT(DISTINCT CASE WHEN d.is_new_user = 1 THEN r.user_id END) * 100.0 / 
          NULLIF(COUNT(DISTINCT r.user_id), 0), 2) as new_user_ratio,
    
    -- ไป˜่ดน็ปŸ่ฎก๏ผˆ7ๆ—ฅๅ†…๏ผ‰
    COUNT(DISTINCT CASE WHEN p.pay_time IS NOT NULL THEN r.user_id END) as pay_users,
    SUM(IFNULL(p.pay_amount, 0)) as total_revenue,
    ROUND(SUM(IFNULL(p.pay_amount, 0)) / NULLIF(SUM(gc.cost), 0), 2) as roi_7d,
    
    -- ็”จๆˆท่ดจ้‡ๆŒ‡ๆ ‡
    ROUND(AVG(d.user_level), 1) as avg_user_level,
    ROUND(AVG(d.user_total_recharge), 2) as avg_ltv
    
FROM channel c
LEFT JOIN gift_code gc ON c.channel_id = gc.channel_id
LEFT JOIN gift_code_redeem_log r ON gc.id = r.code_id AND r.status = 1
LEFT JOIN dwd_gift_code_redeem_detail d ON r.id = d.redeem_id
LEFT JOIN (
    SELECT user_id, MIN(pay_time) as pay_time, SUM(amount) as pay_amount
    FROM user_payment
    WHERE pay_time <= DATE_ADD(redeem_time, INTERVAL 7 DAY)
    GROUP BY user_id
) p ON r.user_id = p.user_id
WHERE gc.created_at >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
GROUP BY c.channel_id, c.channel_name, c.channel_type
ORDER BY roi_7d DESC;

3.4 ๆ—ถ้—ด็ฑปๆŒ‡ๆ ‡

็Žฉๅฎถไป€ไนˆๆ—ถๅ€™ๆœ€ๆดป่ทƒ๏ผŸไป€ไนˆๆ—ถๅ€™ๆœ€ๅฎนๆ˜“็œ‹ๅˆฐๆŽจ้€๏ผŸ่ฟ™ไธชๆŒ‡ๆ ‡ๅธฎๅŠฉไผ˜ๅŒ–ๆŠ•ๆ”พๅ’ŒๆŽจ้€ๆ—ถๆœบใ€‚

-- ๅ…‘ๆขๆ—ถๆฎต็ƒญๅŠ›ๅ›พๆ•ฐๆฎ๏ผˆๅฐๆ—ถ x ๆ˜ŸๆœŸ๏ผ‰
SELECT 
    day_of_week,
    redeem_hour,
    COUNT(*) as redeem_count,
    ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 4) as percentage,
    -- ไธŽๅนณๅ‡ๅ€ผๆฏ”่พƒ
    ROUND(COUNT(*) * 1.0 / AVG(COUNT(*)) OVER(), 2) as index_vs_avg
FROM dwd_gift_code_redeem_detail
WHERE status = 1
  AND redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
GROUP BY day_of_week, redeem_hour
ORDER BY day_of_week, redeem_hour;

-- ็”Ÿๆˆ็ƒญๅŠ›ๅ›พๆ•ฐๆฎๆ ผๅผ๏ผˆๅฏ็›ดๆŽฅ็”จไบŽๅ‰็ซฏๅฑ•็คบ๏ผ‰
SELECT 
    CONCAT('[', GROUP_CONCAT(
        CONCAT('{x:', redeem_hour, ',y:', day_of_week - 1, ',value:', redeem_count, '}')
        ORDER BY day_of_week, redeem_hour
    ), ']') as heatmap_data
FROM (
    SELECT day_of_week, redeem_hour, COUNT(*) as redeem_count
    FROM dwd_gift_code_redeem_detail
    WHERE status = 1 AND redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY day_of_week, redeem_hour
) t;

3.5 ๅฅ–ๅŠฑ็ฑปๆŒ‡ๆ ‡

ๅ“ช็งๅฅ–ๅŠฑๆœ€ๅ—ๆฌข่ฟŽ๏ผŸๅ“ช็งๅฅ–ๅŠฑๅ…‘ๆขๅŽ็”จๆˆทๆปกๆ„ๅบฆๆœ€้ซ˜๏ผŸๅ“ช็งๅฅ–ๅŠฑๅฏน็•™ๅญ˜็š„่ดก็Œฎๆœ€ๅคง๏ผŸ

-- ๅฅ–ๅŠฑๆ•ˆๆžœ็ปผๅˆๅˆ†ๆž
SELECT 
    reward_id,
    reward_name,
    reward_type,
    reward_value,
    
    -- ็ƒญๅบฆๆŒ‡ๆ ‡
    COUNT(*) as redeem_count,
    COUNT(DISTINCT user_id) as unique_users,
    RANK() OVER (ORDER BY COUNT(*) DESC) as popularity_rank,
    
    -- ๆปกๆ„ๅบฆไปฃ็†ๆŒ‡ๆ ‡๏ผˆๅ…‘ๆขๅŽ7ๆ—ฅๆดป่ทƒๅคฉๆ•ฐ๏ผ‰
    ROUND(AVG(active_days_7d), 1) as avg_active_days_7d,
    
    -- ไป˜่ดน่ฝฌๅŒ–
    COUNT(DISTINCT CASE WHEN has_paid_7d = 1 THEN user_id END) as pay_convert_users,
    ROUND(COUNT(DISTINCT CASE WHEN has_paid_7d = 1 THEN user_id END) * 100.0 / 
          NULLIF(COUNT(DISTINCT user_id), 0), 2) as pay_convert_rate,
    
    -- ็•™ๅญ˜่ดก็Œฎ
    ROUND(AVG(day7_retention) * 100, 2) as avg_day7_retention_pct,
    
    -- ROI
    ROUND(SUM(total_pay_7d) / NULLIF(reward_value * COUNT(*), 0), 2) as roi
    
FROM (
    SELECT 
        d.reward_id,
        d.reward_name,
        d.reward_type,
        d.reward_value,
        d.user_id,
        COUNT(DISTINCT u.active_date) as active_days_7d,
        MAX(CASE WHEN p.pay_time IS NOT NULL THEN 1 ELSE 0 END) as has_paid_7d,
        SUM(IFNULL(p.amount, 0)) as total_pay_7d,
        MAX(CASE WHEN u.active_date = DATE_ADD(d.redeem_date, INTERVAL 7 DAY) THEN 1 ELSE 0 END) as day7_retention
    FROM dwd_gift_code_redeem_detail d
    LEFT JOIN user_daily_active u ON d.user_id = u.user_id 
        AND u.active_date BETWEEN d.redeem_date AND DATE_ADD(d.redeem_date, INTERVAL 7 DAY)
    LEFT JOIN user_payment p ON d.user_id = p.user_id 
        AND p.pay_time BETWEEN d.redeem_time AND DATE_ADD(d.redeem_time, INTERVAL 7 DAY)
    WHERE d.status = 1
      AND d.redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY d.reward_id, d.reward_name, d.reward_type, d.reward_value, d.user_id
) reward_user
GROUP BY reward_id, reward_name, reward_type, reward_value
ORDER BY redeem_count DESC;

ๅ››ใ€ๆŠฅ่กจ็ณป็ปŸ่ฎพ่ฎก

ๆŒ‡ๆ ‡ๆœ‰ไบ†๏ผŒๆŽฅไธ‹ๆฅๆ˜ฏๅฆ‚ไฝ•ๅ‘ˆ็Žฐใ€‚ๅฅฝ็š„ๆŠฅ่กจ็ณป็ปŸ๏ผŒ่ฆๅƒไธ€ไฝไผ˜็ง€็š„ๅˆ†ๆžๅธˆโ€”โ€”ไธไป…ๅฑ•็คบๆ•ฐๆฎ๏ผŒ่ฟ˜่ฆ่ฎฒๆธ…ๆฅšๆ•ฐๆฎ่ƒŒๅŽ็š„ๆ•…ไบ‹ใ€‚

4.1 ๆŠฅ่กจๅˆ†ๅฑ‚ๆžถๆž„

ๆŠฅ่กจ็ณป็ปŸๅบ”่ฏฅๅƒๆด‹่‘ฑไธ€ๆ ท๏ผŒไธ€ๅฑ‚ไธ€ๅฑ‚ๅ‰ฅๅผ€๏ผš

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    ็ฌฌไธ€ๅฑ‚๏ผšๆฆ‚่งˆๅคงๅฑ                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”           โ”‚
โ”‚  โ”‚ไปŠๆ—ฅๅ…‘ๆข้‡โ”‚ โ”‚ๅ…‘ๆข็އ   โ”‚ โ”‚ๆดป่ทƒๆดปๅŠจ โ”‚ โ”‚ๅผ‚ๅธธ้ข„่ญฆ โ”‚           โ”‚
โ”‚  โ”‚12,345   โ”‚ โ”‚67.8%    โ”‚ โ”‚15ไธช     โ”‚ โ”‚2ไธช      โ”‚           โ”‚
โ”‚  โ”‚โ†‘ 15%    โ”‚ โ”‚โ†“ 3.2%   โ”‚ โ”‚โ†‘ 3ไธช    โ”‚ โ”‚โš ๏ธ       โ”‚           โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚                  ่ถ‹ๅŠฟๅ›พ่กจ๏ผˆๆŠ˜็บฟๅ›พ๏ผ‰                      โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                    ็ฌฌไบŒๅฑ‚๏ผš็ปดๅบฆๅˆ†ๆž                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚    ๆธ ้“ๅˆ†ๆž        โ”‚  โ”‚    ๆ—ถ้—ดๅˆ†ๆž        โ”‚               โ”‚
โ”‚  โ”‚  (ๆŸฑ็Šถๅ›พ/ๆกๅฝขๅ›พ)   โ”‚  โ”‚  (็ƒญๅŠ›ๅ›พ/ๆ—ฅๅކๅ›พ)   โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚    ๅฅ–ๅŠฑๅˆ†ๆž        โ”‚  โ”‚    ็”จๆˆทๅˆ†ๆž        โ”‚               โ”‚
โ”‚  โ”‚  (้ฅผๅ›พ/็Žฏๅฝขๅ›พ)     โ”‚  โ”‚  (ๆผๆ–—ๅ›พ/้›ท่พพๅ›พ)   โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                    ็ฌฌไธ‰ๅฑ‚๏ผšๆ˜Ž็ป†ๆŸฅ่ฏข                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  ็ญ›้€‰ๆกไปถ๏ผš[ๆดปๅŠจ] [ๆธ ้“] [ๆ—ถ้—ด] [ๅฅ–ๅŠฑ] [ๆ›ดๅคš โ–ผ]        โ”‚  โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
โ”‚  โ”‚  ็”จๆˆทID โ”‚ๅ…‘ๆขๆ—ถ้—ดโ”‚ๅฅ–ๅŠฑโ”‚ๆธ ้“โ”‚็Šถๆ€โ”‚ๆ“ไฝœ                 โ”‚  โ”‚
โ”‚  โ”‚  10001 โ”‚02-28 15:30โ”‚้ป„้‡‘็คผๅŒ…โ”‚ๅพฎไฟกโ”‚ๆˆๅŠŸโ”‚[่ฏฆๆƒ…]        โ”‚  โ”‚
โ”‚  โ”‚  10002 โ”‚02-28 15:29โ”‚็™ฝ้“ถ็คผๅŒ…โ”‚ๆŠ–้Ÿณโ”‚ๆˆๅŠŸโ”‚[่ฏฆๆƒ…]        โ”‚  โ”‚
โ”‚  โ”‚  ...   โ”‚...        โ”‚...    โ”‚... โ”‚... โ”‚...            โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  [ๅฏผๅ‡บCSV] [ๅฏผๅ‡บExcel]                                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฟ่ฅ่ดŸ่ดฃไบบๆ‰“ๅผ€ๆŠฅ่กจ๏ผŒ็ฌฌไธ€็œผ็œ‹ๅˆฐ็š„ๆ˜ฏไป€ไนˆ๏ผŸ

่ฟ™ไธ€ๅฑ‚ๅ›ž็ญ”็š„้—ฎ้ข˜ๆ˜ฏ๏ผšๆ•ดไฝ“ๆƒ…ๅ†ตๅฆ‚ไฝ•๏ผŸๆœ‰ๆฒกๆœ‰้œ€่ฆ็ซ‹ๅณๅ…ณๆณจ็š„้—ฎ้ข˜๏ผŸ

ไปŽๆฆ‚่งˆๅ‘็Žฐๅผ‚ๅธธๅŽ๏ผŒ้œ€่ฆไธ‹้’ปๅˆ†ๆžใ€‚ๆ”ฏๆŒๅคš็ปดๅบฆไบคๅ‰ๅˆ†ๆž๏ผŒๆฏ”ๅฆ‚"ๆ–ฐ็”จๆˆทๅœจๅ‘จๆœซๅฏนๅ„ๅฅ–ๅŠฑ็ฑปๅž‹็š„ๅๅฅฝ"ใ€‚

้œ€่ฆ็œ‹ๅˆฐๅ…ทไฝ“็š„ๆ•ฐๆฎๆ—ถ๏ผŒๆ”ฏๆŒ็ตๆดป็ญ›้€‰ๅ’Œๆ•ฐๆฎๅฏผๅ‡บใ€‚

4.2 ๅฏ่ง†ๅŒ–ๅ›พ่กจ่ฎพ่ฎก

ไธๅŒ็š„ๆ•ฐๆฎ๏ผŒ้€‚ๅˆไธๅŒ็š„ๅ›พ่กจใ€‚้€‰้”™ๅ›พ่กจ็ฑปๅž‹๏ผŒไผš่ฎฉๆ•ฐๆฎๅ˜ๅพ—้šพไปฅ็†่งฃใ€‚้€‰ๆ‹ฉๆญฃ็กฎ็š„ๅ›พ่กจ็ฑปๅž‹๏ผŒ่ƒฝ่ฎฉๆ•ฐๆฎ่‡ชๅทฑ่ฏด่ฏใ€‚

ๅˆ†ๆž็›ฎ็š„ ๆŽจ่ๅ›พ่กจ ้€‚็”จๅœบๆ™ฏ ็คบไพ‹
็œ‹่ถ‹ๅŠฟ ๆŠ˜็บฟๅ›พใ€้ข็งฏๅ›พ ๅ…‘ๆข้‡้šๆ—ถ้—ดๅ˜ๅŒ– ๆ—ฅๅ…‘ๆข้‡่ถ‹ๅŠฟ
็œ‹ๅ ๆฏ” ้ฅผๅ›พใ€็Žฏๅฝขๅ›พใ€ๆ ‘ๅ›พ ๅ„ๆธ ้“ๅ…‘ๆขๅ ๆฏ” ๆธ ้“ๅˆ†ๅธƒ
็œ‹ๅฏนๆฏ” ๆŸฑ็Šถๅ›พใ€ๆกๅฝขๅ›พ ไธๅŒๆดปๅŠจๆ•ˆๆžœๅฏนๆฏ” ๆดปๅŠจๅ…‘ๆข็އๆŽ’ๅ
็œ‹ๅˆ†ๅธƒ ็›ดๆ–นๅ›พใ€็ฎฑ็บฟๅ›พ ็”จๆˆทๅ…‘ๆขๆฌกๆ•ฐๅˆ†ๅธƒ ไบบๅ‡ๅ…‘ๆขๅˆ†ๅธƒ
็œ‹ๅ…ณ็ณป ๆ•ฃ็‚นๅ›พใ€ๆฐ”ๆณกๅ›พ ๅ…‘ๆข็އๅ’Œ็•™ๅญ˜็š„ๅ…ณ็ณป ROI vs ็•™ๅญ˜ๆ•ฃ็‚น
็œ‹ๅฏ†ๅบฆ ็ƒญๅŠ›ๅ›พ ๆ—ถๆฎตๆดป่ทƒๅˆ†ๅธƒ ๅ…‘ๆขๆ—ถๆฎต็ƒญๅŠ›ๅ›พ
็œ‹ๆต็จ‹ ๆผๆ–—ๅ›พใ€ๆก‘ๅŸบๅ›พ ็”จๆˆท่ฝฌๅŒ–่ทฏๅพ„ ไปŽๆ›ๅ…‰ๅˆฐๅ…‘ๆข

4.2.1 ่ถ‹ๅŠฟๆŠ˜็บฟๅ›พ๏ผˆๅธฆ้ข„่ญฆ็บฟ๏ผ‰

ๅ…‘ๆข้‡่ถ‹ๅŠฟๅ›พ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  1500 โ”ค                          โ•ญโ”€โ”€โ”€โ•ฎ                 โ”‚
โ”‚       โ”‚                        โ•ญโ•ฏ    โ•ฒ                โ”‚
โ”‚  1200 โ”ค                   โ•ญโ”€โ”€โ”€โ•ฏ      โ•ฒ   โ•ญโ”€โ”€โ•ฎ        โ”‚
โ”‚       โ”‚              โ•ญโ”€โ”€โ”€โ•ฏ           โ•ฒโ”€โ•ฏ   โ•ฒ         โ”‚
โ”‚   900 โ”ค        โ•ญโ”€โ”€โ”€โ•ฎโ•ฏ                         โ•ฒ       โ”‚
โ”‚       โ”‚   โ•ญโ”€โ”€โ”€โ•ฏ    โ•ฒ                            โ•ฒโ”€โ”€โ•ฎ โ”‚
โ”‚   600 โ”คโ”€โ”€โ”€โ•ฏ         โ•ฒ                              โ•ฒโ”€โ”‚
โ”‚       โ”‚                                            โ•ฒ โ”‚
โ”‚   300 โ”ค โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€โ”‚ โ† ้ข„่ญฆ็บฟ
โ”‚       โ”‚                                              โ•ฒโ”‚
โ”‚     0 โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚
โ”‚       02-22  02-23  02-24  02-25  02-26  02-27  02-28โ”‚
โ”‚                                                       โ”‚
โ”‚  โ”โ”โ” ไปŠๆ—ฅ    โ”„โ”„โ”„ ๆ˜จๆ—ฅ    โ–ฒ ๅณฐๅ€ผ    โš  ๅผ‚ๅธธ็‚น         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฎพ่ฎก่ฆ็‚น๏ผš

4.2.2 ๆธ ้“ๅฏนๆฏ”ๆŸฑ็Šถๅ›พ

ๆธ ้“ๆ•ˆๆžœๅฏนๆฏ”๏ผˆๆŒ‰ๅ…‘ๆข็އๆŽ’ๅบ๏ผ‰
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                        โ”‚
โ”‚  ๅพฎไฟกๅฐ็จ‹ๅบ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  89.2%    โ”‚
โ”‚  ๆŠ–้Ÿณ     โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  76.5%          โ”‚
โ”‚  B็ซ™      โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  65.3%                โ”‚
โ”‚  ๅพฎๅš     โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  52.1%                    โ”‚
โ”‚  ๅฐ็บขไนฆ   โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  43.8%                        โ”‚
โ”‚  QQ      โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  31.2%                            โ”‚
โ”‚  ๅฎ˜็ฝ‘     โ–ˆโ–ˆโ–ˆโ–ˆ  18.5%                                โ”‚
โ”‚                                                        โ”‚
โ”‚  โ”โ”โ” ๅ…‘ๆข็އ    โ”โ”โ” ้ข„่ญฆ้˜ˆๅ€ผ(40%)                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฎพ่ฎก่ฆ็‚น๏ผš

4.2.3 ๆ—ถๆฎต็ƒญๅŠ›ๅ›พ

ๅ…‘ๆขๆ—ถๆฎต็ƒญๅŠ›ๅ›พ๏ผˆ้ขœ่‰ฒ่ถŠๆทฑ = ๅ…‘ๆข่ถŠๆดป่ทƒ๏ผ‰
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        0  2  4  6  8 10 12 14 16 18 20 22             โ”‚
โ”‚  ๅ‘จไธ€  โ–‘  โ–‘  โ–‘  โ–’  โ–’  โ–“  โ–“  โ–’  โ–’  โ–“  โ–“  โ–’            โ”‚
โ”‚  ๅ‘จไบŒ  โ–‘  โ–‘  โ–‘  โ–’  โ–’  โ–“  โ–“  โ–’  โ–’  โ–“  โ–“  โ–’            โ”‚
โ”‚  ๅ‘จไธ‰  โ–‘  โ–‘  โ–‘  โ–’  โ–’  โ–“  โ–“  โ–’  โ–’  โ–“  โ–“  โ–’            โ”‚
โ”‚  ๅ‘จๅ››  โ–‘  โ–‘  โ–‘  โ–’  โ–’  โ–“  โ–“  โ–’  โ–’  โ–“  โ–“  โ–’            โ”‚
โ”‚  ๅ‘จไบ”  โ–‘  โ–‘  โ–‘  โ–’  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“            โ”‚
โ”‚  ๅ‘จๅ…ญ  โ–’  โ–’  โ–’  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“            โ”‚
โ”‚  ๅ‘จๆ—ฅ  โ–’  โ–’  โ–’  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“  โ–“            โ”‚
โ”‚                                                        โ”‚
โ”‚  โ–‘ ไฝŽๆดป่ทƒ  โ–’ ไธญ็ญ‰  โ–“ ้ซ˜ๆดป่ทƒ  โ–ˆ ๅณฐๅ€ผ                   โ”‚
โ”‚                                                        โ”‚
โ”‚  ๐Ÿ’ก ๆœ€ไฝณๆŽจ้€ๆ—ถๆฎต๏ผšๅ‘จๆœซ 14:00-20:00                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฎพ่ฎก่ฆ็‚น๏ผš

4.2.4 ็”จๆˆท่ฝฌๅŒ–ๆผๆ–—

็”จๆˆท่ฝฌๅŒ–ๆผๆ–—ๅˆ†ๆž
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                        โ”‚
โ”‚  ๆดปๅŠจๆ›ๅ…‰    100,000  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚
โ”‚     โ†“  45%                                            โ”‚
โ”‚  ็‚นๅ‡ป่ฟ›ๅ…ฅ     45,000  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ      โ”‚
โ”‚     โ†“  62%                                            โ”‚
โ”‚  ่Žทๅ–็คผๅŒ…็    27,900  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ            โ”‚
โ”‚     โ†“  78%                                            โ”‚
โ”‚  ๆ‰“ๅผ€ๆธธๆˆ     21,762  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                โ”‚
โ”‚     โ†“  85%                                            โ”‚
โ”‚  ๆˆๅŠŸๅ…‘ๆข     18,498  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                  โ”‚
โ”‚     โ†“  72%                                            โ”‚
โ”‚  7ๆ—ฅ็•™ๅญ˜     13,318   โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                    โ”‚
โ”‚                                                        โ”‚
โ”‚  ๆ•ดไฝ“่ฝฌๅŒ–็އ๏ผš18.5%    ๅ…ณ้”ฎๆตๅคฑ็‚น๏ผš็‚นๅ‡ปโ†’่Žทๅ–็           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

่ฎพ่ฎก่ฆ็‚น๏ผš

4.3 ๅฎžๆ—ถ vs ็ฆป็บฟๆŠฅ่กจ

-- ๅฎžๆ—ถ็›‘ๆŽงSQL็คบไพ‹๏ผˆClickHouse๏ผ‰
SELECT 
    'current_redeem_count' as metric,
    COUNT(*) as value,
    'ๆฌก' as unit,
    (SELECT COUNT(*) FROM gift_code_redeem_log 
     WHERE redeem_time >= DATE_SUB(NOW(), INTERVAL 1 DAY)) as compare_value,
    ROUND((COUNT(*) - compare_value) * 100.0 / NULLIF(compare_value, 0), 2) as change_rate
FROM gift_code_redeem_log
WHERE redeem_time >= toStartOfMinute(NOW() - INTERVAL 5 MINUTE);

-- ๅฎžๆ—ถๅผ‚ๅธธๆฃ€ๆต‹
SELECT 
    activity_id,
    DATE_FORMAT(redeem_time, '%Y-%m-%d %H:%i') as minute,
    COUNT(*) as redeem_count,
    CASE 
        WHEN COUNT(*) > 1000 THEN 'ALERT'   -- ่ถ…่ฟ‡1000ๆฌก/ๅˆ†้’Ÿๅ‘Š่ญฆ
        WHEN COUNT(*) > 500 THEN 'WARNING'  -- ่ถ…่ฟ‡500ๆฌก/ๅˆ†้’Ÿ้ข„่ญฆ
        ELSE 'NORMAL'
    END as status
FROM gift_code_redeem_log
WHERE redeem_time >= DATE_SUB(NOW(), INTERVAL 10 MINUTE)
GROUP BY activity_id, DATE_FORMAT(redeem_time, '%Y-%m-%d %H:%i')
HAVING status != 'NORMAL';

็ฆป็บฟๆŠฅ่กจๅฏไปฅๅšๆ›ดๅคๆ‚็š„่ฎก็ฎ—๏ผŒๆฏ”ๅฆ‚็”จๆˆท็•™ๅญ˜ๅˆ†ๆžใ€LTV่ฎก็ฎ—ใ€ๅฝ’ๅ› ๅˆ†ๆž็ญ‰ใ€‚

4.4 ๆŠฅ่กจๆ€ง่ƒฝไผ˜ๅŒ–

ๅฝ“ๆ•ฐๆฎ้‡่พพๅˆฐๅƒไธ‡็บง็”š่‡ณไบฟ็บงๆ—ถ๏ผŒๆŠฅ่กจๆŸฅ่ฏขๆ€ง่ƒฝๅฐฑๆˆไบ†ๅ…ณ้”ฎ้—ฎ้ข˜ใ€‚

ๆŠŠ็ปๅธธๆŸฅ่ฏข็š„ๆŒ‡ๆ ‡้ข„ๅ…ˆ่ฎก็ฎ—ๅฅฝ๏ผŒๅญ˜ๅ…ฅๆฑ‡ๆ€ป่กจใ€‚

-- ๆฏๆ—ฅๅ‡Œๆ™จๆ‰ง่กŒ้ข„่šๅˆ
INSERT INTO dws_activity_daily_summary
SELECT 
    activity_id,
    CURRENT_DATE - INTERVAL 1 DAY as stat_date,
    -- ... ๅ„็ง่šๅˆๆŒ‡ๆ ‡
FROM dwd_gift_code_redeem_detail
WHERE redeem_date = CURRENT_DATE - INTERVAL 1 DAY
GROUP BY activity_id;

ๆŒ‰ๆ—ฅๆœŸๅˆ†ๅŒบ๏ผŒๆŸฅ่ฏขๆ—ถๅชๆ‰ซๆ้œ€่ฆ็š„ๅˆ†ๅŒบใ€‚

-- ๅˆ›ๅปบๅˆ†ๅŒบ่กจ
CREATE TABLE dwd_gift_code_redeem_detail (
    -- ๅญ—ๆฎตๅฎšไน‰...
) PARTITION BY RANGE (TO_DAYS(redeem_date)) (
    PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),
    PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')),
    PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')),
    -- ...
);

-- ๆŸฅ่ฏขๆ—ถ่‡ชๅŠจๅˆฉ็”จๅˆ†ๅŒบ่ฃๅ‰ช
SELECT * FROM dwd_gift_code_redeem_detail
WHERE redeem_date >= '2026-02-01' AND redeem_date < '2026-03-01';
-- ๅชไผšๆ‰ซๆ p202602 ๅˆ†ๅŒบ

ๅฏนไบŽๅคๆ‚็š„ๅˆ†ๆžๆŸฅ่ฏข๏ผŒๅฏไปฅๅˆ›ๅปบ็‰ฉๅŒ–่ง†ๅ›พใ€‚

-- ๅˆ›ๅปบ็‰ฉๅŒ–่ง†ๅ›พ๏ผˆ่‡ชๅŠจๅˆทๆ–ฐ๏ผ‰
CREATE MATERIALIZED VIEW mv_channel_daily_stats
REFRESH FAST ON DEMAND
AS SELECT 
    channel_id,
    redeem_date,
    COUNT(*) as redeem_count,
    COUNT(DISTINCT user_id) as unique_users,
    -- ... ๅ…ถไป–ๆŒ‡ๆ ‡
FROM dwd_gift_code_redeem_detail
GROUP BY channel_id, redeem_date;

ๅฏนไบŽ้ซ˜้ข‘ๆŸฅ่ฏข็š„็ป“ๆžœ๏ผŒๅฏไปฅ็ผ“ๅญ˜่ตทๆฅใ€‚

ๆŸฅ่ฏข่ฏทๆฑ‚ โ†’ Redis็ผ“ๅญ˜ โ†’ ๅ‘ฝไธญ๏ผŸโ†’ ่ฟ”ๅ›ž็ป“ๆžœ
                โ†“ ๆœชๅ‘ฝไธญ
            ๆ•ฐๆฎๅบ“ๆŸฅ่ฏข โ†’ ๅ†™ๅ…ฅ็ผ“ๅญ˜ โ†’ ่ฟ”ๅ›ž็ป“ๆžœ

็ผ“ๅญ˜็ญ–็•ฅ๏ผš


ไบ”ใ€ๆ•ฐๆฎๅˆ†ๆžๆ–นๆณ•่ฎบ

ๆœ‰ไบ†ๆ•ฐๆฎๅ’ŒๆŠฅ่กจ๏ผŒๆŽฅไธ‹ๆฅๆ˜ฏๅฆ‚ไฝ•ๅˆ†ๆžใ€‚ๅˆ†ๆžไธๆ˜ฏ็ฎ€ๅ•็š„"็œ‹ๆ•ฐๆฎ"๏ผŒ่€Œๆ˜ฏ่ฆๆœ‰ๆ–นๆณ•ใ€ๆœ‰้€ป่พ‘ใ€ๆœ‰็ป“่ฎบใ€‚

5.1 ่ถ‹ๅŠฟๅˆ†ๆžๆณ•

ไปŠๅคฉ็š„ๅ…‘ๆข้‡ๆ˜ฏ5000๏ผŒ่ฟ™ไธชๆ•ฐๅญ—ๆœฌ่บซๆฒกๆœ‰ๆ„ไน‰ใ€‚ไธŠๅ‘จไบ”ๆ˜ฏ4000๏ผŒไธŠไธŠๅ‘จๆ˜ฏ3000โ€”โ€”ๅขž้•ฟ่ถ‹ๅŠฟๅพˆๆ˜Žๆ˜พใ€‚

  1. ็กฎๅฎšๅŸบๅ‡†็บฟ๏ผš้€‰ๆ‹ฉๅˆ้€‚็š„ๅฏนๆฏ”ๅ‘จๆœŸ๏ผˆ็Žฏๆฏ”/ๅŒๆฏ”/็›ฎๆ ‡๏ผ‰
  2. ่ฏ†ๅˆซ่ถ‹ๅŠฟๆ–นๅ‘๏ผšไธŠๅ‡/ไธ‹้™/ๆŒๅนณ
  3. ๅˆคๆ–ญ่ถ‹ๅŠฟๅผบๅบฆ๏ผš็ผ“ๆ…ข/ไธญ็ญ‰/ๅ‰ง็ƒˆ
  4. ้ข„ๆต‹ๆœชๆฅ่ตฐๅ‘๏ผšๅŸบไบŽๅކๅฒ่ง„ๅพ‹
-- ่ถ‹ๅŠฟๅˆ†ๆžSQL๏ผš่ฎก็ฎ—็งปๅŠจๅนณๅ‡ๅ’Œ่ถ‹ๅŠฟ
WITH daily_stats AS (
    SELECT 
        redeem_date,
        COUNT(*) as daily_redeems
    FROM dwd_gift_code_redeem_detail
    WHERE redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY redeem_date
),
with_ma AS (
    SELECT 
        redeem_date,
        daily_redeems,
        -- 7ๆ—ฅ็งปๅŠจๅนณๅ‡
        AVG(daily_redeems) OVER (
            ORDER BY redeem_date 
            ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
        ) as ma_7d,
        -- ็Žฏๆฏ”ๅ˜ๅŒ–
        LAG(daily_redeems) OVER (ORDER BY redeem_date) as prev_day,
        -- ๅŒๆฏ”ๅ˜ๅŒ–
        LAG(daily_redeems, 7) OVER (ORDER BY redeem_date) as prev_week
    FROM daily_stats
)
SELECT 
    redeem_date,
    daily_redeems,
    ma_7d,
    ROUND(ma_7d - LAG(ma_7d) OVER (ORDER BY redeem_date), 2) as ma_trend,
    ROUND((daily_redeems - prev_day) * 100.0 / NULLIF(prev_day, 0), 2) as dod_change,
    ROUND((daily_redeems - prev_week) * 100.0 / NULLIF(prev_week, 0), 2) as wow_change,
    CASE 
        WHEN daily_redeems > ma_7d * 1.2 THEN 'ABOVE_NORMAL'
        WHEN daily_redeems < ma_7d * 0.8 THEN 'BELOW_NORMAL'
        ELSE 'NORMAL'
    END as status
FROM with_ma
ORDER BY redeem_date DESC;
ๅ…‘ๆข้‡่ถ‹ๅŠฟๅˆ†ๆž๏ผˆๅซ็งปๅŠจๅนณๅ‡๏ผ‰
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  2000 โ”ค                    โ•ญโ”€โ”€โ•ฎ                        โ”‚
โ”‚       โ”‚    ยท    ยท      โ•ญโ”€โ”€โ•ฏ   โ•ฒ    ยท                  โ”‚
โ”‚  1500 โ”ค  ยท   ยท    โ•ญโ”€โ”€โ”€โ•ฏ       โ•ฒโ”€โ”€โ•ฎ   ยท   ยท            โ”‚
โ”‚       โ”‚ยท          โ•ฑ              โ•ฒ                  ยท โ”‚
โ”‚  1000 โ”คโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฑโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฒโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ยทโ”€โ”€โ”€โ”‚ โ† 7ๆ—ฅMA
โ”‚       โ”‚    ยท    ยท    ยท     ยท    ยท    โ•ฒ   ยท   ยท       โ”‚
โ”‚   500 โ”ค                              โ•ฒ               โ”‚
โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฒโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚        02-01 02-05 02-10 02-15 02-20 02-25 02-28     โ”‚
โ”‚                                                        โ”‚
โ”‚  ยท ๆ—ฅๅ…‘ๆข้‡    โ”โ”โ” 7ๆ—ฅ็งปๅŠจๅนณๅ‡                        โ”‚
โ”‚                                                        โ”‚
โ”‚  ๐Ÿ“Š ๅˆ†ๆž็ป“่ฎบ๏ผš                                         โ”‚
โ”‚  โ€ข ๆ•ดไฝ“ๅ‘ˆไธŠๅ‡่ถ‹ๅŠฟ๏ผŒ7ๆ—ฅMAไปŽ800ๅ‡่‡ณ1200 (+50%)          โ”‚
โ”‚  โ€ข 02-15ๅ‡บ็Žฐๅผ‚ๅธธๅณฐๅ€ผ๏ผŒ้œ€ๅ…ณๆณจๅŽŸๅ›                        โ”‚
โ”‚  โ€ข ่ฟ‘3ๆ—ฅ็จณๅฎšๅœจMA้™„่ฟ‘๏ผŒ่ถ‹ๅŠฟๅฅๅบท                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

5.2 ๅฝ’ๅ› ๅˆ†ๆžๆณ•

ๆ•ฐๆฎๅผ‚ๅธธไบ†๏ผŒๆ€Žไนˆๆ‰พๅŽŸๅ› ๏ผŸ้€š่ฟ‡็ปดๅบฆไธ‹้’ปๅ’Œ็›ธๅ…ณๆ€งๅˆ†ๆžใ€‚

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  ๆ€ปไฝ“ๆŒ‡ๆ ‡ๅ˜ๅŒ–    โ”‚
                    โ”‚  (ๅฆ‚ๅ…‘ๆข็އไธ‹้™)  โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                             โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ–ผ              โ–ผ              โ–ผ
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚ ๆธ ้“็ปดๅบฆ โ”‚    โ”‚ ๆ—ถ้—ด็ปดๅบฆ โ”‚    โ”‚ ็”จๆˆท็ปดๅบฆ โ”‚
        โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜
             โ”‚              โ”‚              โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”
        โ–ผ    โ–ผ    โ–ผ    โ–ผ    โ–ผ    โ–ผ    โ–ผ    โ–ผ    โ–ผ
       ๅพฎไฟก ๆŠ–้Ÿณ ...   ๅ‘จๆœซ ๅทฅไฝœๆ—ฅ ...  ๆ–ฐ็”จๆˆท ่€็”จๆˆท ...
-- ๅฝ’ๅ› ๅˆ†ๆž๏ผšๆ‰พๅˆฐๅ…‘ๆข็އไธ‹้™็š„ๆ นๆœฌๅŽŸๅ› 
WITH base_metrics AS (
    -- ๅŸบๅ‡†ๆœŸ๏ผˆไธŠๅ‘จ๏ผ‰
    SELECT 
        channel_id,
        'baseline' as period,
        COUNT(DISTINCT gc.id) as total_codes,
        COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) as redeemed,
        ROUND(COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) * 100.0 / 
              NULLIF(COUNT(DISTINCT gc.id), 0), 2) as redeem_rate
    FROM gift_code gc
    WHERE gc.created_at BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 14 DAY) 
                            AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
    GROUP BY channel_id
    
    UNION ALL
    
    -- ๅฏนๆฏ”ๆœŸ๏ผˆๆœฌๅ‘จ๏ผ‰
    SELECT 
        channel_id,
        'current' as period,
        COUNT(DISTINCT gc.id) as total_codes,
        COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) as redeemed,
        ROUND(COUNT(DISTINCT CASE WHEN gc.status = 1 THEN gc.id END) * 100.0 / 
              NULLIF(COUNT(DISTINCT gc.id), 0), 2) as redeem_rate
    FROM gift_code gc
    WHERE gc.created_at >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
    GROUP BY channel_id
)
SELECT 
    c.channel_name,
    MAX(CASE WHEN period = 'baseline' THEN redeem_rate END) as baseline_rate,
    MAX(CASE WHEN period = 'current' THEN redeem_rate END) as current_rate,
    MAX(CASE WHEN period = 'current' THEN redeem_rate END) - 
    MAX(CASE WHEN period = 'baseline' THEN redeem_rate END) as rate_change,
    -- ่ดก็Œฎๅบฆ่ฎก็ฎ—
    ROUND((MAX(CASE WHEN period = 'current' THEN redeemed END) - 
           MAX(CASE WHEN period = 'baseline' THEN redeemed END)) * 100.0 /
          NULLIF((SELECT SUM(CASE WHEN period = 'current' THEN redeemed END) - 
                        SUM(CASE WHEN period = 'baseline' THEN redeemed END)
                  FROM base_metrics WHERE period != 'total'), 0), 2) as contribution_pct
FROM base_metrics b
JOIN channel c ON b.channel_id = c.channel_id
GROUP BY c.channel_name
ORDER BY rate_change ASC;
๐Ÿ“‹ ๅ…‘ๆข็އไธ‹้™ๅฝ’ๅ› ๅˆ†ๆžๆŠฅๅ‘Š
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

๐Ÿ“Œ ้—ฎ้ข˜ๆ่ฟฐ
  โ€ข ๆ€ปไฝ“ๅ…‘ๆข็އไปŽ 68.5% ไธ‹้™่‡ณ 52.3% (-16.2pp)
  โ€ข ๅฝฑๅ“่Œƒๅ›ด๏ผšๅ…จๆธ ้“
  โ€ข ๆŒ็ปญๆ—ถ้—ด๏ผš่ฟ‘7ๅคฉ

๐Ÿ” ๅฝ’ๅ› ๅˆ†ๆž

  ใ€ๆธ ้“็ปดๅบฆใ€‘
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ ๆธ ้“    โ”‚ ๅŸบๅ‡†ๆœŸ โ”‚ ๆœฌๆœŸ   โ”‚ ๅ˜ๅŒ–   โ”‚ ่ดก็Œฎๅบฆ โ”‚
  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
  โ”‚ ๅพฎๅš    โ”‚ 72.3%  โ”‚ 31.2%  โ”‚ -41.1ppโ”‚ 45.2%  โ”‚ โ† ไธป่ฆๅŽŸๅ› 
  โ”‚ ๅฐ็บขไนฆ  โ”‚ 58.6%  โ”‚ 42.1%  โ”‚ -16.5ppโ”‚ 28.3%  โ”‚
  โ”‚ ๆŠ–้Ÿณ    โ”‚ 81.2%  โ”‚ 68.5%  โ”‚ -12.7ppโ”‚ 18.5%  โ”‚
  โ”‚ ๅพฎไฟก    โ”‚ 65.4%  โ”‚ 63.2%  โ”‚  -2.2ppโ”‚  8.0%  โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  
  ใ€ๆ—ถ้—ด็ปดๅบฆใ€‘
  โ€ข ๅทฅไฝœๆ—ฅๅฝฑๅ“ๆ›ดๅคง๏ผˆ-18.3pp vs ๅ‘จๆœซ-8.6pp๏ผ‰
  โ€ข ๆ™š้—ดๆ—ถๆฎต๏ผˆ18:00-22:00๏ผ‰ไธ‹้™ๆœ€ๆ˜Žๆ˜พ

๐Ÿ’ก ๆ นๅ› ๅฎšไฝ
  1. ๅพฎๅšๆธ ้“ๆŠ•ๆ”พ็ญ–็•ฅๅ˜ๆ›ด๏ผˆๆ–ฐๆŽฅๅ…ฅไบ†ๅญๆธ ้“X๏ผ‰
  2. ๅญๆธ ้“X็”จๆˆท่ดจ้‡่พƒๅทฎ๏ผŒๅ…‘ๆข็އไป…15%
  3. ๆ‹‰ไฝŽไบ†ๅพฎๅšๆ•ดไฝ“ๅ…‘ๆข็އ

โœ… ๅปบ่ฎฎๆŽชๆ–ฝ
  1. ๆš‚ๅœๅญๆธ ้“XๆŠ•ๆ”พ
  2. ๅพฎๅšๆธ ้“้‡ๆ–ฐ่ฏ„ไผฐROI
  3. ๅปบ็ซ‹ๆธ ้“ๅ‡†ๅ…ฅๆœบๅˆถ

5.3 ๆผๆ–—ๅˆ†ๆžๆณ•

็”จๆˆทไปŽ็œ‹ๅˆฐๆดปๅŠจๅˆฐๆˆๅŠŸๅ…‘ๆข๏ผŒ้œ€่ฆ็ป่ฟ‡ๅคšไธชๆญฅ้ชคใ€‚ๆฏไธชๆญฅ้ชค้ƒฝๆœ‰ๆตๅคฑ๏ผŒๆผๆ–—ๅˆ†ๆžๅธฎๅŠฉๆ‰พๅ‡บ้—ฎ้ข˜ๆœ€ๅคง็š„็Žฏ่Š‚ใ€‚

-- ๆผๆ–—ๅˆ†ๆžSQL
WITH funnel_steps AS (
    SELECT 
        user_id,
        -- ๆญฅ้ชค1๏ผšๆดปๅŠจๆ›ๅ…‰
        MAX(CASE WHEN event_type = 'activity_expose' THEN event_time END) as step1_time,
        -- ๆญฅ้ชค2๏ผš็‚นๅ‡ป่ฟ›ๅ…ฅ
        MAX(CASE WHEN event_type = 'activity_click' THEN event_time END) as step2_time,
        -- ๆญฅ้ชค3๏ผš่Žทๅ–็คผๅŒ…็ 
        MAX(CASE WHEN event_type = 'get_code' THEN event_time END) as step3_time,
        -- ๆญฅ้ชค4๏ผšๆ‰“ๅผ€ๆธธๆˆ
        MAX(CASE WHEN event_type = 'open_game' THEN event_time END) as step4_time,
        -- ๆญฅ้ชค5๏ผšๆˆๅŠŸๅ…‘ๆข
        MAX(CASE WHEN event_type = 'redeem_success' THEN event_time END) as step5_time
    FROM user_event_log
    WHERE activity_id = 1001
      AND event_date BETWEEN '2026-02-01' AND '2026-02-28'
    GROUP BY user_id
)
SELECT 
    'ๆญฅ้ชค1: ๆดปๅŠจๆ›ๅ…‰' as step_name,
    COUNT(*) as user_count,
    100.00 as conversion_rate,
    0 as drop_rate
FROM funnel_steps WHERE step1_time IS NOT NULL

UNION ALL

SELECT 
    'ๆญฅ้ชค2: ็‚นๅ‡ป่ฟ›ๅ…ฅ',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM funnel_steps WHERE step1_time IS NOT NULL), 2),
    ROUND(100 - COUNT(*) * 100.0 / (SELECT COUNT(*) FROM funnel_steps WHERE step1_time IS NOT NULL), 2)
FROM funnel_steps 
WHERE step2_time IS NOT NULL 
  AND step2_time > step1_time

UNION ALL

SELECT 
    'ๆญฅ้ชค3: ่Žทๅ–็คผๅŒ…็ ',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM funnel_steps WHERE step1_time IS NOT NULL), 2),
    ROUND(100 - COUNT(*) * 100.0 / (SELECT COUNT(*) FROM funnel_steps WHERE step2_time IS NOT NULL), 2)
FROM funnel_steps 
WHERE step3_time IS NOT NULL 
  AND step3_time > step2_time

-- ... ็ปง็ปญๅ…ถไป–ๆญฅ้ชค
;
ๆตๅคฑ็Žฏ่Š‚ ๅฏ่ƒฝๅŽŸๅ›  ไผ˜ๅŒ–ๅปบ่ฎฎ
ๆ›ๅ…‰โ†’็‚นๅ‡ป ๆดปๅŠจๅŒ…่ฃ…ไธๅคŸๅธๅผ• ไผ˜ๅŒ–ๆดปๅŠจๅ›พ็‰‡ใ€ๆ–‡ๆกˆ
็‚นๅ‡ปโ†’่Žทๅ–็  ่Žทๅ–ๆต็จ‹ๅคชๅคๆ‚ ็ฎ€ๅŒ–ๆ“ไฝœๆญฅ้ชค
่Žทๅ–็ โ†’ๆ‰“ๅผ€ๆธธๆˆ ๆฒกๆœ‰ๅผ•ๅฏผ็”จๆˆท ๆทปๅŠ ไธ€้”ฎ่ทณ่ฝฌ
ๆ‰“ๅผ€ๆธธๆˆโ†’ๅ…‘ๆข ๆ‰พไธๅˆฐๅ…‘ๆขๅ…ฅๅฃ ๅ…‘ๆขๅ…ฅๅฃๅ‰็ฝฎใ€ๅผน็ช—ๅผ•ๅฏผ

5.4 ๅŒๆœŸ็พคๅˆ†ๆž๏ผˆCohort Analysis๏ผ‰

ๆŠŠๅŒไธ€ๆ—ถๆœŸ๏ผˆๅŒไธ€ๅคฉ/ๅŒไธ€ๅ‘จ/ๅŒไธ€ๆœˆ๏ผ‰ๅผ€ๅง‹ไฝฟ็”จไบงๅ“็š„็”จๆˆทๅˆ†ไธบไธ€็ป„๏ผŒ่ฟฝ่ธชไป–ไปฌๅŽ็ปญ็š„่กŒไธบใ€‚

-- ๅŒๆœŸ็พค็•™ๅญ˜ๅˆ†ๆžSQL
WITH user_cohort AS (
    -- ๆŒ‰็”จๆˆท้ฆ–ๆฌกๅ…‘ๆขๆ—ฅๆœŸๅˆ†็ป„
    SELECT 
        user_id,
        MIN(DATE(redeem_time)) as cohort_date
    FROM dwd_gift_code_redeem_detail
    WHERE status = 1
    GROUP BY user_id
),
cohort_activity AS (
    -- ่ฎก็ฎ—ๆฏไธช็”จๆˆทๅœจๆฏไธชๆ—ถๆฎต็š„ๆดป่ทƒๆƒ…ๅ†ต
    SELECT 
        c.cohort_date,
        DATEDIFF(a.active_date, c.cohort_date) as days_since_first,
        COUNT(DISTINCT c.user_id) as active_users
    FROM user_cohort c
    LEFT JOIN user_daily_active a ON c.user_id = a.user_id
    WHERE c.cohort_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY c.cohort_date, DATEDIFF(a.active_date, c.cohort_date)
)
SELECT 
    cohort_date,
    SUM(CASE WHEN days_since_first = 0 THEN active_users ELSE 0 END) as day0,
    SUM(CASE WHEN days_since_first = 1 THEN active_users ELSE 0 END) as day1,
    SUM(CASE WHEN days_since_first = 7 THEN active_users ELSE 0 END) as day7,
    SUM(CASE WHEN days_since_first = 14 THEN active_users ELSE 0 END) as day14,
    SUM(CASE WHEN days_since_first = 30 THEN active_users ELSE 0 END) as day30,
    -- ่ฎก็ฎ—็•™ๅญ˜็އ
    ROUND(SUM(CASE WHEN days_since_first = 7 THEN active_users ELSE 0 END) * 100.0 /
          NULLIF(SUM(CASE WHEN days_since_first = 0 THEN active_users ELSE 0 END), 0), 2) as day7_retention
FROM cohort_activity
GROUP BY cohort_date
ORDER BY cohort_date DESC;
็”จๆˆท็•™ๅญ˜ๅŒๆœŸ็พคๅˆ†ๆž๏ผˆๆŒ‰้ฆ–ๆฌกๅ…‘ๆขๅ‘จๅˆ†็ป„๏ผ‰
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
           โ”‚ ็ฌฌ1ๅ‘จ  โ”‚ ็ฌฌ2ๅ‘จ  โ”‚ ็ฌฌ3ๅ‘จ  โ”‚ ็ฌฌ4ๅ‘จ  โ”‚ ็ฌฌ5ๅ‘จ  โ”‚ ็ฌฌ6ๅ‘จ
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€
2026-W01   โ”‚ 5,000  โ”‚ 3,250  โ”‚ 2,750  โ”‚ 2,400  โ”‚ 2,150  โ”‚ 1,950
           โ”‚ 100%   โ”‚ 65%    โ”‚ 55%    โ”‚ 48%    โ”‚ 43%    โ”‚ 39%
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€
2026-W02   โ”‚ 6,200  โ”‚ 4,092  โ”‚ 3,224  โ”‚ 2,790  โ”‚ 2,480  โ”‚
           โ”‚ 100%   โ”‚ 66%    โ”‚ 52%    โ”‚ 45%    โ”‚ 40%    โ”‚
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€
2026-W03   โ”‚ 4,800  โ”‚ 3,120  โ”‚ 2,544  โ”‚ 2,112  โ”‚        โ”‚
           โ”‚ 100%   โ”‚ 65%    โ”‚ 53%    โ”‚ 44%    โ”‚        โ”‚
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€
2026-W04   โ”‚ 7,500  โ”‚ 5,025  โ”‚ 3,975  โ”‚        โ”‚        โ”‚
           โ”‚ 100%   โ”‚ 67%    โ”‚ 53%    โ”‚        โ”‚        โ”‚
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

๐Ÿ“Š ๅˆ†ๆž็ป“่ฎบ๏ผš
โ€ข ็ฌฌ2ๅ‘จ็•™ๅญ˜็จณๅฎšๅœจ65-67%๏ผŒ่กจ็Žฐ่‰ฏๅฅฝ
โ€ข ็ฌฌ4ๅ‘จ็•™ๅญ˜็บฆ44-48%๏ผŒๆœ‰ๆๅ‡็ฉบ้—ด
โ€ข W04ๆ‰นๆฌก็”จๆˆท่ดจ้‡ๆœ€ไฝณ๏ผŒๅฏๆŒ็ปญๅ…ณๆณจ

5.5 ๅผ‚ๅธธๆฃ€ๆต‹ๆ–นๆณ•

ๅฝ“ๆ•ฐๆฎ้‡ๅพˆๅคงๆ—ถ๏ผŒ้ ไบบๅทฅๅ‘็Žฐๅผ‚ๅธธๆ˜ฏไธ็Žฐๅฎž็š„ใ€‚้œ€่ฆๅปบ็ซ‹่‡ชๅŠจๅŒ–็š„ๅผ‚ๅธธๆฃ€ๆต‹ๆœบๅˆถใ€‚

ๅŸบไบŽๅކๅฒๆ•ฐๆฎ็š„ๅ‡ๅ€ผๅ’Œๆ ‡ๅ‡†ๅทฎ่ฎพๅฎš้˜ˆๅ€ผใ€‚

-- ็ปŸ่ฎก้˜ˆๅ€ผๆณ•๏ผš3ฯƒๅŽŸๅˆ™
WITH daily_stats AS (
    SELECT 
        redeem_date,
        COUNT(*) as daily_redeems
    FROM dwd_gift_code_redeem_detail
    WHERE redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 90 DAY)
    GROUP BY redeem_date
),
stats AS (
    SELECT 
        AVG(daily_redeems) as mean_value,
        STDDEV(daily_redeems) as std_value
    FROM daily_stats
)
SELECT 
    d.redeem_date,
    d.daily_redeems,
    s.mean_value,
    s.std_value,
    (d.daily_redeems - s.mean_value) / s.std_value as z_score,
    CASE 
        WHEN ABS((d.daily_redeems - s.mean_value) / s.std_value) > 3 THEN 'ANOMALY'
        WHEN ABS((d.daily_redeems - s.mean_value) / s.std_value) > 2 THEN 'WARNING'
        ELSE 'NORMAL'
    END as status
FROM daily_stats d
CROSS JOIN stats s
ORDER BY ABS(z_score) DESC;

ไธŽไธŠไธ€ไธชๅ‘จๆœŸๅฏนๆฏ”๏ผŒๅ˜ๅŒ–่ถ…่ฟ‡้˜ˆๅ€ผๅˆ™ๅ‘Š่ญฆใ€‚

-- ็Žฏๆฏ”ๅ˜ๅŒ–ๅ‘Š่ญฆ
SELECT 
    activity_id,
    redeem_date,
    daily_redeems,
    prev_day_redeems,
    ROUND((daily_redeems - prev_day_redeems) * 100.0 / NULLIF(prev_day_redeems, 0), 2) as change_pct,
    CASE 
        WHEN change_pct > 50 THEN 'ALERT_UP'    -- ไธŠๆถจ่ถ…่ฟ‡50%
        WHEN change_pct < -50 THEN 'ALERT_DOWN' -- ไธ‹่ทŒ่ถ…่ฟ‡50%
        WHEN change_pct > 30 THEN 'WARNING_UP'
        WHEN change_pct < -30 THEN 'WARNING_DOWN'
        ELSE 'NORMAL'
    END as status
FROM (
    SELECT 
        activity_id,
        redeem_date,
        COUNT(*) as daily_redeems,
        LAG(COUNT(*)) OVER (PARTITION BY activity_id ORDER BY redeem_date) as prev_day_redeems
    FROM dwd_gift_code_redeem_detail
    WHERE redeem_date >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
    GROUP BY activity_id, redeem_date
) t
WHERE ABS(change_pct) > 30;

็ป“ๅˆๅŒๆฏ”ๅ’Œ็Žฏๆฏ”๏ผŒๆ›ดๅ‡†็กฎๅœฐๅˆคๆ–ญๅผ‚ๅธธใ€‚

-- ๅŒ็Žฏๆฏ”่”ๅˆๆฃ€ๆต‹
SELECT 
    metric_name,
    metric_date,
    current_value,
    prev_day_value,
    prev_week_value,
    ROUND((current_value - prev_day_value) * 100.0 / NULLIF(prev_day_value, 0), 2) as dod_change,
    ROUND((current_value - prev_week_value) * 100.0 / NULLIF(prev_week_value, 0), 2) as wow_change,
    CASE 
        -- ๅŒ็Žฏๆฏ”ๅŒๆ—ถๅคงๅน…ไธŠๆถจ/ไธ‹่ทŒ๏ผŒๆ›ดๅฏ่ƒฝๆ˜ฏ็œŸๅฎžๅผ‚ๅธธ
        WHEN dod_change > 30 AND wow_change > 30 THEN 'STRONG_ALERT_UP'
        WHEN dod_change < -30 AND wow_change < -30 THEN 'STRONG_ALERT_DOWN'
        -- ไป…็Žฏๆฏ”ๅ˜ๅŒ–๏ผŒๅฏ่ƒฝๆ˜ฏๅ‘จๆœŸๆ€งๆณขๅŠจ
        WHEN ABS(dod_change) > 30 AND ABS(wow_change) < 15 THEN 'WEAK_WARNING'
        ELSE 'NORMAL'
    END as alert_level
FROM daily_metrics
WHERE metric_date = CURRENT_DATE - INTERVAL 1 DAY;

ๅ…ญใ€่ฟ่ฅๅ†ณ็ญ–ๆ”ฏๆŒ

ๆ•ฐๆฎๅˆ†ๆž็š„ๆœ€็ปˆ็›ฎ็š„๏ผŒๆ˜ฏๆ”ฏๆŒ่ฟ่ฅๅ†ณ็ญ–ใ€‚ๆ•ฐๆฎไธๆ˜ฏ็ปˆ็‚น๏ผŒๅ†ณ็ญ–ๆ‰ๆ˜ฏใ€‚

6.1 ๆดปๅŠจไผ˜ๅŒ–ๅ†ณ็ญ–

ๆ นๆฎๆ•ฐๆฎ่ฐƒๆ•ดๅฅ–ๅŠฑ้…็ฝฎ๏ผš

-- ๅฅ–ๅŠฑๆ•ˆๆžœๅˆ†ๆž๏ผŒๆŒ‡ๅฏผไผ˜ๅŒ–
SELECT 
    reward_type,
    COUNT(*) as redeem_count,
    AVG(day7_retention) as avg_retention,
    AVG(pay_convert_rate) as avg_convert,
    -- ็ปผๅˆ่ฏ„ๅˆ† = ็ƒญๅบฆ*0.3 + ็•™ๅญ˜*0.4 + ่ฝฌๅŒ–*0.3
    ROUND((redeem_count / max_redeems * 30) + 
          (avg_retention * 40) + 
          (avg_convert * 30), 2) as composite_score
FROM reward_analysis
GROUP BY reward_type
ORDER BY composite_score DESC;
๐ŸŽฏ ๅฅ–ๅŠฑไผ˜ๅŒ–ๅปบ่ฎฎ
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

ใ€ไฟ็•™ใ€‘้ป„้‡‘็คผๅŒ…ใ€้’ป็Ÿณ็คผๅŒ…
  โ€ข ็ปผๅˆ่ฏ„ๅˆ† > 80
  โ€ข ็•™ๅญ˜่ดก็Œฎ้ซ˜๏ผŒ็”จๆˆทๆปกๆ„ๅบฆ้ซ˜

ใ€ไผ˜ๅŒ–ใ€‘็™ฝ้“ถ็คผๅŒ…
  โ€ข ็ƒญๅบฆไธญ็ญ‰๏ผŒไฝ†่ฝฌๅŒ–ๅไฝŽ
  โ€ข ๅปบ่ฎฎ๏ผšๅขžๅŠ ้ขๅค–ๅฐๅฅ–ๅŠฑๆๅ‡ๅธๅผ•ๅŠ›

ใ€ๆ›ฟๆขใ€‘้“œๅธ็คผๅŒ…
  โ€ข ็ปผๅˆ่ฏ„ๅˆ† < 40
  โ€ข ็”จๆˆทๅ้ฆˆ"ๅฅ–ๅŠฑๅคชๅฐ‘"
  โ€ข ๅปบ่ฎฎ๏ผšๆ›ฟๆขไธบๆŠฝๅฅ–ๅˆธๆˆ–้™ๆ—ถ้“ๅ…ท

6.2 ๆธ ้“ไผ˜ๅŒ–ๅ†ณ็ญ–

-- ๆธ ้“ROI็ปผๅˆ่ฏ„ไผฐ
SELECT 
    channel_name,
    total_cost,
    total_revenue,
    ROUND(total_revenue / NULLIF(total_cost, 0), 2) as roi,
    -- LTV้ข„ๆต‹๏ผˆ็ฎ€ๅŒ–็‰ˆ๏ผš30ๆ—ฅๆ”ถๅ…ฅ * 3๏ผ‰
    ROUND(total_revenue_30d * 3 / NULLIF(total_cost, 0), 2) as predicted_ltv_roi,
    -- ๅปบ่ฎฎๅŠจไฝœ
    CASE 
        WHEN roi >= 2 THEN 'SCALE_UP'      -- ๆ‰ฉๅคงๆŠ•ๆ”พ
        WHEN roi >= 1 THEN 'MAINTAIN'      -- ็ปดๆŒๆŠ•ๆ”พ
        WHEN roi >= 0.5 THEN 'OPTIMIZE'    -- ไผ˜ๅŒ–ๆŠ•ๆ”พ
        ELSE 'PAUSE'                        -- ๆš‚ๅœๆŠ•ๆ”พ
    END as suggested_action
FROM channel_roi_summary
ORDER BY roi DESC;

6.3 ้ฃŽ้™ฉ้ข„่ญฆ็ณป็ปŸ

-- ้ฃŽ้™ฉ็›‘ๆŽงไปช่กจ็›˜SQL
SELECT 
    '้ซ˜้ข‘ๅ…‘ๆข' as risk_type,
    COUNT(*) as risk_count,
    GROUP_CONCAT(DISTINCT code_id) as affected_codes
FROM (
    SELECT code_id, COUNT(*) as cnt
    FROM gift_code_redeem_log
    WHERE redeem_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
    GROUP BY code_id
    HAVING cnt > 10
) t

UNION ALL

SELECT 
    'IPๅผ‚ๅธธ' as risk_type,
    COUNT(DISTINCT redeem_ip) as risk_count,
    GROUP_CONCAT(DISTINCT redeem_ip) as affected_ips
FROM gift_code_redeem_log
WHERE redeem_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY redeem_ip
HAVING COUNT(*) > 100

UNION ALL

SELECT 
    '่ฎพๅค‡ๅ…ณ่”' as risk_type,
    COUNT(DISTINCT device_id) as risk_count,
    ''
FROM (
    SELECT device_id, COUNT(DISTINCT user_id) as user_cnt
    FROM gift_code_redeem_log
    WHERE redeem_time >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
    GROUP BY device_id
    HAVING user_cnt > 5
) t;

``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ้ฃŽ้™ฉๆฃ€ๆต‹ โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ ้ฃŽ้™ฉ่ฏ„ไผฐ โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ ้ข„่ญฆ้€š็Ÿฅ โ”‚ โ”‚ (ๅฎžๆ—ถ็›‘ๆŽง) โ”‚ โ”‚ (่‡ชๅŠจๅˆ†็บง) โ”‚ โ”‚ (ๅคšๆธ ้“) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ไบบๅทฅ็กฎ่ฎค โ”‚ โ”‚ (ๅฏ้€‰) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๅค„็ฝฎๆŽชๆ–ฝ โ”‚ โ”‚ (่‡ชๅŠจ/ๆ‰‹ๅŠจ) โ”‚ โ””

๐Ÿ’ฌ ่ฏ„่ฎบ (0)

0/500
ๆŽ’ๅบ๏ผš