简化MySQL查询

时间:2010-02-23 11:05:33

标签: sql mysql

我有一个需要简化的工作查询。

原因是我需要对其进行大量扩展以涵盖实际应用。对于每个条件(Pos = xxx AND Indata = yyy),当前查询的大小加倍,并且我有很多条件。此外,ON子句将包含比示例中更多的条件....

真正的应用程序将有大约20个Pos / Indata条件(这里只有3个)和其他20个必须匹配的字段(这里只有1个)。

查询的作用,在“伪代码”中解释:

find all rows with (Pos=xx1 AND Indata=yy1) as t1
union
all rows with (Pos=xx2 AND Indata=yy2) as t2
then join t1 and t2 to keep only rows where other fields match (t1.fields=t2.fields OR t1.fields=* OR t2.fields=*)
you could store this in a temp table temp1

then find all rows with (Pos=xx3 AND Indata=yy3) as t3
union
temp1
then join t3 and temp1 to keep only rows where other fields match (t3.fields=temp1.fields OR t3.fields=* OR temp1.fields=*)
you could store this in a temp table temp2

then find all rows with (Pos=xx4 AND Indata=yy4) as t4
union
temp2
join t4 and temp4 to keep only rows where other fields match (t4.fields=temp4.fields OR t4.fields=* OR temp4.fields=*)
you could store this in a temp table temp2
等等....我基本上想找到所有行表“代码”与某些Pos和Indata,其中大多数其他字段相互匹配....一个可能的解决方案可能是临时表加上一点PHP作为在上面的伪代码....但它只能在SQL中解决....

SELECT t15.* FROM (
    (
        SELECT DISTINCT t6.* FROM (
            (
                SELECT t5.* FROM (
                    (
                        SELECT DISTINCT t1.* FROM (
                            (SELECT * FROM codes WHERE (Pos = 10 AND Indata = 'Rexroth')) AS t1
                            JOIN (
                                (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t2
                            ) ON (t1.Manufacturer = t2.Manufacturer OR t1.Manufacturer='*' OR t2.Manufacturer='*')
                        )
                    ) UNION (
                        SELECT DISTINCT t4.* FROM (
                            (SELECT * FROM codes WHERE (Pos = 10 AND Indata = 'Rexroth')) AS t3
                            JOIN (
                                (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t4
                            ) ON (t3.Manufacturer = t4.Manufacturer OR t3.Manufacturer='*' OR t4.Manufacturer='*')
                        )
                    )
                ) AS t5
            ) AS t6

            JOIN (
                (
                    SELECT * FROM codes WHERE (Pos = 70 AND Indata = '28 cm3')
                ) AS t7
            ) ON (t7.Manufacturer = t6.Manufacturer OR t7.Manufacturer='*' OR t6.Manufacturer='*')
        )
    ) UNION (
        SELECT DISTINCT t14.* FROM (
            (
                SELECT t12.* FROM (
                    (
                        SELECT DISTINCT t8.* FROM (
                            (SELECT * FROM codes WHERE (Pos = 10 AND Indata = 'Rexroth')) AS t8
                            JOIN (
                                (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t9
                            ) ON (t9.Manufacturer = t8.Manufacturer OR t9.Manufacturer='*' OR t8.Manufacturer='*')
                        )
                    ) UNION (
                        SELECT DISTINCT t11.* FROM (
                            (SELECT * FROM codes WHERE (Pos = 10 AND Indata = 'Rexroth')) AS t10
                            JOIN (
                                (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t11
                            ) ON (t11.Manufacturer = t10.Manufacturer OR t11.Manufacturer='*' OR t10.Manufacturer='*')
                        )
                    )
                ) AS t12
            ) AS t13
            JOIN (
                (
                    SELECT * FROM codes WHERE (Pos = 70 AND Indata = '28 cm3')
                ) AS t14
            ) ON (t13.Manufacturer = t14.Manufacturer OR t13.Manufacturer='*' OR t14.Manufacturer='*')
        )
    )
) AS t15

我刚刚用temp表重写了它,似乎至少更容易阅读:

CREATE TEMPORARY TABLE temp
SELECT * FROM codes WHERE (Pos = 10 AND Indata = 'Rexroth');

CREATE TEMPORARY TABLE temp2
SELECT DISTINCT t1.* FROM (
    (SELECT * FROM temp) AS t1
    JOIN (
        (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t2
    ) ON (t1.Manufacturer = t2.Manufacturer OR t1.Manufacturer='*' OR t2.Manufacturer='*')
);
INSERT INTO temp2
SELECT DISTINCT t2.* FROM (
    (SELECT * FROM temp) AS t1
    JOIN (
        (SELECT * FROM codes WHERE (Pos = 30 AND Indata = '%Mineralolja')) AS t2
    ) ON (t1.Manufacturer = t2.Manufacturer OR t1.Manufacturer='*' OR t2.Manufacturer='*')
);

DROP TABLE temp;
ALTER TABLE temp2 RENAME temp;

CREATE TEMPORARY TABLE temp2
SELECT DISTINCT t1.* FROM (
    (SELECT * FROM temp) AS t1
    JOIN (
        (SELECT * FROM codes WHERE (Pos = 70 AND Indata = '28 cm3')) AS t2
    ) ON (t1.Manufacturer = t2.Manufacturer OR t1.Manufacturer='*' OR t2.Manufacturer='*')
);
INSERT INTO temp2
SELECT DISTINCT t2.* FROM (
    (SELECT * FROM temp) AS t1
    JOIN (
        (SELECT * FROM codes WHERE (Pos = 70 AND Indata = '28 cm3')) AS t2
    ) ON (t1.Manufacturer = t2.Manufacturer OR t1.Manufacturer='*' OR t2.Manufacturer='*')
);

SELECT * FROM temp2;

2 个答案:

答案 0 :(得分:1)

这里有很多关于存储过程和临时表的说法 - 正如你自己建议的那样。

例如,即使是现在你的SQL也很难阅读:我看着它并立刻想到“太长了,真的不想读”: - )

过程和工作台可以让未来的开发人员更容易阅读和扩展生活 - 自己包括在6个月的时间内!

您还可以从procs和工作表中获得性能优势:您可以将索引放在工作表上,一次调试一个proc,看看瓶颈在哪里等等。

我想我推荐:赞成使用单个查询的“优雅”的可读性和可扩展性,如果在任何一种方法中都可以认为性能或多或少相等。

答案 1 :(得分:0)

正如布莱恩所说:

  ......太长了,真的不想看了..

但是我试过,我认为你的“Where's”总会有这样的结构:

SELECT * FROM codes WHERE Pos = number AND/LIKE Indata =/% 'somethin' and some how "Manufactor"

所以我会尝试“转动选择”并使用主键 - 很难解释 -

我尝试:第一步:

Select PK from codes where CRITERIA1
union (all)* 
Select PK from codes where CRITERIA2
union (all)*
Select PK from codes where CRITERIA3

所以你得到一个漂亮的选择和一个只有一个col的结果集:主键(PK)[*表示如果“uninon”或“uninon all”表现更好,它取决于你的行数]

来解决这个问题
select [distinct] * from codes where codes.pk in (
      Select PK from codes where CRITERIA1
      union 
     ....
     till CRITERIA42
)