从结构不良的表中提取房屋销售数据

时间:2015-05-29 22:53:44

标签: mysql

我收到了大量的房屋销售数据表。在全表中,有3548个独特的城镇,约有100,000名销售人员。我的目标是大致了解哪个城镇拥有最多的房屋。不幸的是,不同的城镇都被塞进了一个领域。

+----+--------------+-------------+-------------+-----------------+
| id |  salesperson | salesAmount |  unitsSold  |     town        |
+----+--------------+-------------+-------------+-----------------+
| 1       Joe          245000            4        Brentwood;      |
|                                                 Marksburg;      |
|                                                 Orange Heights; |
+-----------------------------------------------------------------+
| 2       Sally        783290            6        Oak Hills;      |
|                                                 Jacksonville;   |
|                                                 Brentwood;      |
+-----------------------------------------------------------------+
| 3       Bob          398000            2        Eastport;       |
|                                                 Marksburg;      |
+-----------------------------------------------------------------+

我们想说我想知道布伦特伍德销售的大概数额。我可以运行这样的查询:

 SELECT SUM(salesAmount), SUM(unitsSold) from mytable WHERE town LIKE '%Brentwood%';

这并不完美,因为,例如,我们在第1行中并不知道布伦特伍德房屋的售价是多少。 但是我仍然可以很好地了解城镇房屋的销售情况。

我真的很想按下数据来获得一个如下表格:

+----+--------------+-------------------+------------------+
| id |   town       | salesAmountTotal  |  unitsSoldTotal  |         
+----+--------------+-------------------+------------------+
| 1     Brentwood      5,028,290                32         |
|                                                          |
+----------------------------------------------------------+
| 2     Oak Hills      3,783290                 18         |
|                                                          |
+----------------------------------------------------------+
| 3     Eastport       1,398,000                 6         |
|                                                          |
+----------------------------------------------------------+

我的老板真的不在乎谁卖了什么,但她确实关心它在哪个城镇出售。

如何提取销售数据以获得上述表格?

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

只有一个答案。你不能用这种结构做到这一点,因为你永远不会知道有多少人正在为一个城镇出售。

答案 1 :(得分:1)

可以拆分城镇名称,并确定每个销售人员的销售城镇数量。这样,您至少可以计算每个人每个房产的平均价值,以及每人平均销售的数量或单位。

这些平均值可以再次由城镇聚合,最终您会得到如下所示的查询。它是嵌套的,三层深,但您可以分别执行每个内部查询以查看其结果。

我担心这些平均值是你能得到的最好的。无论您进行查询的复杂程度如何,都没有更多细节需要拆分。

技术细分

您可以在下面找到一个查询和一个小提琴的链接。下面的查询使用了许多技巧:

号码生成器

首先,它会生成一个数字列表。您可以通过从表中选择行并使用变量为每行指定一个数字来生成数字。如果你没有大表,你可以通过选择常量值伪造一个。在下面的内部查询中,我选择了10个值。然后我再次选择10个值并交叉连接这两个列表,总共生成100个值(它的笛卡尔积,因此,行数乘以)。您需要拥有的数字是一个销售人员在城镇列表中拥有的最多(或更多)城镇数量。我认为100应该足够了,但你可以通过添加一个交叉连接来使其成为1000。

有关其他示例,请参阅this answer

拆分城镇名称

这使用SUBSTRING_INDEX。该函数可以获取字符串的第一个或最后一部分,直到给定分隔符的 Nth 出现。因此,通过指定字符串A,B,C,D和索引2,您得到A,B,C'。

然后再次应用该函数,使用负索引,得到最后一部分。这样,您就可以从列表中隔离一个城镇名称。

有关此功能,请参阅a random resource

获取城镇数量

这是通过比较城镇列表的长度,减去删除分隔符后相同字符串的长度来完成的。在您的示例数据中,列表末尾有一个分隔符,我认为总是如此。如果没有,你需要添加1(或者首先更新数据,所以总是有一个,因为它本身也需要获取城镇名称)。

有关其他示例,请参阅this answer

其余

嗯,其余的只是一些分歧和聚合。它们使查询变得更大,但并不复杂得多。

select
  splittown as town,
  sum(salesAmountPerTown) as totalSalesAmountPerTown,
  sum(unitsSoldPerTown) as totalUnitsSoldPerTown
from
  (select
    splitSalesPerTown.*,
    -- Estimate of sales per town, is units sold and total amount divided by the number of towns.
    unitsSold / nrOfTowns as unitsSoldPerTown,
    salesAmount / nrOfTowns as salesAmountPerTown
  from
    (select
      s.person,
      -- Just the sales amount
      s.salesAmount,
       -- Just the number of units sold.
      s.unitsSold,
      -- Sales amount divided by units sold = avarage amount per unit
      s.salesAmount / s.unitsSold as salesAmountPerUnit,
      -- Separate the towns using the number generator
      SUBSTRING_INDEX(SUBSTRING_INDEX(s.town, ';', r.row), ';', -1) as splittown,
      -- count the number of towns (assumes there is always an extra ';' at the end of the list)
      LENGTH(s.town) - LENGTH(REPLACE(s.town, ';', '')) as nrOfTowns
    from
      sales s
      -- Very ugly number generator. You could make it simpler if you have a large table to base this upon.
      cross join
        (select @row := @row + 1 as row
        from
          (select 0 union all select 1 union all select 2 union all select 3 union all select 4  union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) a
          cross join
          (select 0 union all select 1 union all select 2 union all select 3 union all select 4  union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) b
          cross join (select @row := 0) i) r
    having
      -- skip those rows that don't have a town name
      splittown <> ''
    ) splitSalesPerTown
   ) splitSalesPerPerson
 group by
   town

The proof is in the fiddle

其他想法

您可以使用简化版本来获取唯一的城镇名称,并将其保存在单独的表格中,而不是进行复杂的查询。

之后,您可以使用该表将每个人的销售信息拆分为不同的城镇(同样,在单独的表中)。

最后,您可以汇总这些信息,以获得每个城镇的总数和平均值,从而消除人员。

这种方法可能稍微简单一点,您甚至可以决定下载城镇列表或使用外部工具拆分它们而不是查询。

但由于我不知道你是否可以创建表格,我认为我最好建立一个查询,如果只是为了表明如果你真的可以想要。 ;)

答案 2 :(得分:0)

如果您拥有独特城镇名称的表格,并且您只想大致了解哪个城镇很热,您可以试试这个:

 Select towns.name, (select sum(unitsSold) from mytable where town 
 like '%;'+towns.name+';%' or town like towns.name +';%') AS unitsold from towns

如果要使用金额,请更改列名称。