İlk önce bu ihtiyaç sphinx ile doğdu onu söylim, Sphinxten aldığım ID’ler RANK ve ORDER moda göre zaten dizilmiş, fakat bunu mysql’e gönderdikten sonra bir ORDER işlemi yapmıyorsak, tablomuzun varsayılan dizilişine göre geliyor, yani elimizde ilk 10 oluyor, fakat bu ilk 10 arasındaki sıralamayı sphinx yapmış da biz bunu mysql’e gönderdikten sonra order değişiyor, sphinx gibi dizmek istediğimizde ne yapabiliriz diye araştırıyordum, ilk akla gelen her ID için tekrar veritabanına gitmek, tekrar gitmemek için bir çözüm de uniuon, ama ikisi de performansın taban yaptığı işlemler, mysqlde bunun çok güzel bir çözümü var,

0
FIELD()

php’deki array_search getirebilir akıllara ama fonksiyonun tam olarka nasıl çalıştığını anlamak için şunu deneyebilirsiniz

0
SELECT FIELD(1,0,2,3,1,5,6)

ilk değerin sonraki kaçıncı parametre olduğunu dönüyor, yani yukarıdakinin sonucu 4, 0 id gelirse bu 1, buna göre dizdiğimiz de gerçekten satır istediğimiz sırada geliyor, aklımızda Search to Item, countlarını tutarak bir populerite sistemi vardı, bu populeriteye bunu da eklediğimizde kesinlikle daha kaliteli sonuçlar alacağız.

Örnek bir php kodu

0
1
2
3
4
5
6
7
8
9
10
11
12
 $sp = new SphinxClient();
 $sp->SetServer('localhost',3312);
 $sp->SetMatchMode(SPH_MATCH_ANY);
 $sp->SetRankingMode(SPH_RANK_WORDCOUNT);
 $sp->SetLimits(0,10);
 
 $result = $sp->Query('hello world');
 
if($result['total_found'] > 0)
{
   $found_ids = implode(',',array_keys($result['matches']));
   $q_result = $db->query("SELECT * FROM items WHERE id in({$found_ids}) ORDER BY FIELD(id,{$found_ids})");
}

gerçek bir order oldu tşkler mysql (:
Bu fonksiyonu array_search’e benzetmemden dolayı bir deneme daha yaptım (:

0
SELECT FIELD('test','t','te','tes','test')

sonucun burda da 4 gelmesi fonksiyonu anladığımızı gösteriyor.

Buradaki soru da çok güzel cevabı da paylaşmak istedim ,

http://forums.oracle.com/forums/thread.jspa?messageID=1383006

I have seen this question a couple of time on the net over the last little while. I posted the answer below, and thought I might as well put it on the blog as well. The thread continued on after the initial question to include a bunch of more detail that made my answer not the correct answer. I guess I should have simply asked “Why” instead of trying to figure out what the person really wanted.

Unfortunately I have had to do this in the past:

Don’t drop your table of course, but I wanted this to be complete:

0
1
2
3
4
5
6
7
8
9
DROP TABLE REORDER;
 
CREATE TABLE REORDER
(COLUMN4 NUMBER
,COLUMN3 NUMBER
,COLUMN2 NUMBER
,COLUMN5 NUMBER
,COLUMN1 NUMBER
,COLUMN6 NUMBER
);

Now if you select it the columns come up in the order it was created

0
SELECT * FROM REORDER;

You can simply select the columns in the order you want:

0
SELECT COLUMN1,COLUMN2,COLUMN3,COLUMN4,COLUMN5,COLUMN6 FROM REORDER;

You can create a view that the users can use if you wish:

0
CREATE OR REPLACE VIEW ORDERED_REORDER AS SELECT COLUMN1,COLUMN2,COLUMN3,COLUMN4,COLUMN5,COLUMN6 FROM REORDER;
0
SELECT * FROM ORDERED_REORDER;

clean up

0
DROP VIEW ORDERED_REORDER;

I have done this on SMALLER tables less than a few thousand with 100 million+ rows, I wouldn’t do this without some thorough testing.

change the name of the table

0
RENAME REORDER TO ORIG_REORDER;

create a view to look like the original table

0
CREATE VIEW REORDER AS SELECT COLUMN1,COLUMN2,COLUMN3,COLUMN4,COLUMN5,COLUMN6 FROM ORIG_REORDER;

Now the view looks the way you want:

0
SELECT * FROM REORDER;

You can insert etc:

0
1
2
INSERT INTO REORDER (COLUMN1,COLUMN2,COLUMN3,COLUMN4,COLUMN5,COLUMN6)
VALUES (1,2,3,4,5,6);
COMMIT;

Some apps won’t allow this, they need tables and won’t allow views.
Test test test. But first, I would suggest getting a good business case for this as this is an oddball request. Those requests do exist but get it in writing and see if there isn’t a better way to handle the request.

Oracle için kullandığım ve geliştirmekte olduğum PHP ORM kütüphanemde kompleks sorgulara girdikçe yeteneklerini arttırmam gerektiğini farkettim, veritabanını düşünmeden ORDER BY parametresine bir SUBQUERY yazdım düz mantıkla bu kesinlikle performans kaybıdır diye düşünerek Plan analizi yaptırdım veritabanına ama sonuç beni şaşırttı ve  yeni birşey öğrendim (: ORDER BY için bir subquery kullanmak JOIN den daha hızlıymış (: hemen bir örnek vermek istiyorum

Futbolcuları Takımları ile eşleştirip takım adına göre dizmek istedim.

0
1
SQL > SELECT P.NAME,P.ID  FROM PLAYERS P JOIN CLUBS C ON P.CLUB_ID = C.ID
ORDER BY C.NAME;

bunu kütüphanem yazamazdı ben de ORDER BY kısmına query yazdım ve sorgum bu hale geldi.

0
1
SQL > SELECTNAME,ID FROM PLAYERS P
ORDER BY (SELECT NAME FROM CLUBSC WHERE C.ID = P.CLUB_ID);

ve Plan analizinin sonucu (:
JOIN

0
1
2
3
4
5
6
7
8
Operation
------------------------------
SELECT STATEMENT
 SORT ORDER BY
  MERGE JOIN
   TABLE ACCESS BY INDEX ROWID
    INDEX FULL SCAN
   SORT JOIN
    TABLE ACCESS FULL

SUBQUERY

0
1
2
3
4
5
6
Operation
----------------------------
SELECT STATEMENT
 TABLE ACCESS BY INDEX ROWID
  INDEX UNIQUE SCAN
 SORT ORDER BY
  TABLE ACCESS FULL

Tuning fantazilerine girerseniz aklınızda bulunsun (: iyi çalışmalar,

Mysql’de biçok şey için takla atmak zorunda kalıyoruz. Biçok veritabanı Ranking için çok özel şeyler yapsa da Mysql bu konuya hiç girmemiş maalesef.
Veritabanımızdan aldığımız bir liste örn:Kullanıcılar olsun. kullanıcıları biz ID sırasına dizerken. Puan sıralamasına göre kaçıncı sırada olduğunu yazmamız gerekebilir.

Sıralama yapmak için, veritabanına elemanları o kritere göre dizdirmek zorunda olmamalıyız (ORDER BY PUAN DESC gibi bir ifade yazmak zorunda olmamalıyız, ID sırasına göre dizip PUAN sırasını öğrenebilmeliyiz).  Sizin için 100 Puan ile  3üncü sıradasınız gibi bir açıklamayı veritabanım sayesinde verebilmeliyim.

İlk önce örneklerde kullanacağımız tablo ve verileri oluşturalım.

0
1
2
3
4
5
6
7
8
9
10
CREATE TABLE RANK_USERS
(
 ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
 USERNAME VARCHAR(30) NOT NULL,
 FLEX_POINT INT NOT NULL DEFAULT 0,
 STRENGTH_POINT INT NOT NULL DEFAULT 0
);
-- bu sorguyu çalıştırdıktan sonra 1 satır ekleyip aşağıdaki sorguyu birkaç defa çalıştırıp populasyon sağlayalım
INSERT INTO RANK_USERS
(USERNAME,FLEX_POINT,STRENGTH_POINT)
SELECT 'USER_X',rand()*900,rand()*900 FROM RANK_USERS;
0
1
SET @siralama:=0;
SELECT @siralama:=@siralama+1 AS SIRALAMA,ID FROM RANK_USERS ORDER BY FLEX_POINT

FLEX_POINT alanına göre dizip sıralamayı alabilmek için geçici bir değişken set ediyoruz. ve her satırda artması için +1 yapıyoruz.
fakat bu tek başına işimize yaramıyor. Çünkü biz bu dizilime göre kimin kaçıncı sırada olduğunu zaten anlayabilir ya da programlarımızda bu iterasyonu kendimiz yapabiliriz.

“FLEX_POINT sıralamasına göre 1inci olan oyuncu STRENGTH_PINT sıralamasına göre kaçıncı acaba ?”
yine yukardaki basic sorguya ufak bir şart eklenip tek kullanıcı için bulunabilir, peki bunları sütunlar halinde yanyana görmek istersek ?.
Yöntemi açıklıyorum hemen : sağ elinizde sol kulağınızı başınız arkasından tutmanız gerekiyor (: hadi yapalım o zaman.

0
1
2
3
4
5
6
7
8
9
10
11
12
SET @flexRank:=0;
SET @strRank:=0;
 
SELECT
R.ID,R.USERNAME,flexRankTable.RANK FLEX_RANK,strRankTable.RANK STR_RANK
FROM
RANK_USERS R
JOIN
(SELECT @flexRank:=@flexRank + 1 RANK,RU.* FROM RANK_USERS RU ORDER BY RU.FLEX_POINT DESC) flexRankTable
ON R.ID = flexRankTable.ID
JOIN
(SELECT @strRank:=@strRank + 1 RANK,RU.*  FROM RANK_USERS RU ORDER BY RU.STRENGTH_POINT DESC) strRankTable
ON R.ID = strRankTable.ID

Sonuç :

Evet amacımıza ulaştık ama bunu diğer veritabanları nasıl yapıyor görelim hemen

Mssql

0
1
2
3
SELECT ID,USERNAME
row_number() over(ORDER BY FLEX_POINT DESC)  FLEX_RANK,
row_number() over(ORDER BY STRENGTH_POINT DESC) STR_RANK
RANK_USERS

ayrıca bu örnekler bize veritabanından aldığımız tablodaki satır numarasını veriyor. mysqlde gerçek ranking işlemini hala yapabilmiş değilim yazabilirsem mutlaka paylaşacağım. msqsl için row_numver() yerine rank() kullandığımızda bize gerçek bir ranking yapıyor. ve puanı eşit olanların sıralaması da aynı geliyor.

Oracle’da ise bunu biraz daha abartıp rankingi partitionlara göre ayırabilioruz. örn her yılın 1 incisini ayrı ayrı görebilmek gibi. yıl sütunu eklemeyip ID için mod 10 alıp yapacağım.
her 10 kullanıcıyı kendi arasında 1 den 10 a kadar dizmek istersek puana göre:

0
1
SELECT rank() over (partition BY mod(id,10) ORDER BY FLEX_PINT DESC)
FROM RANK_USERS

olay budur (: mysql’de diğer veritabanlarına benzer rank işlemini de yapabilmek için sanırım bir tur daha dönmek, bir takla daha atmak gibi bi şartımız olacak onu öğrenince blogumdan bulabilirsiniz (:
iyi çalışmalar..

© 2012 Tufan Suffusion theme by Sayontan Sinha