2012-05-21 7 views
5

Tengo una tabla que contiene las transacciones de acciones:consulta SQL para mostrar cambios en la columna "total"

+------+----------------------+------------------+ 
| Item | Running Stock Total | Transaction Time | 
+------+----------------------+------------------+ 
| foo | 4     | 2012-05-12 11:07 | 
| bar | 3     | 2012-05-12 10:42 | 
| bar | 3     | 2012-05-12 9:42 | 
| bar | 2     | 2012-05-11 15:42 | 
| foo | 3     | 2012-05-11 10:02 | 
| bar | 3     | 2012-05-10 13:44 | 
...etc... 
+------+----------------------+------------------+ 

es decir Cada vez que algo le sucede a la acción, una fila se crea en esta mesa-, esto puede significar la acción el nivel sube (nuevo stock ordenado), baja (stock vendido) o permanece sin cambios (stock reubicado).

Necesito crear una consulta sql que devuelva solo las filas donde realmente ha cambiado el nivel de stock para una pieza en particular, y necesita mostrar los cambios en una columna "stock up" y "stock down".

es decir, 1 Item='bar'

+------+-----------+------------+----------------------+------------------+ 
| Item | Stock Up | Stock Down | Running Stock Total | Transaction Time | 
+------+-----------+------------+----------------------+------------------+ 
| bar |  1 |  0  | 3     | 2012-05-12 9:42 | 
| bar |  0 |  1  | 2     | 2012-05-11 15:42 | 
| bar |  1 |  0  | 3     | 2012-05-10 13:44 | 
+------+-----------+------------+----------------------+------------------+ 

e.g.2 Item='foo'

+------+-----------+------------+----------------------+------------------+ 
| Item | Stock Up | Stock Down | Running Stock Total | Transaction Time | 
+------+-----------+------------+----------------------+------------------+ 
| foo |  1 |  0  | 4     | 2012-05-12 11:07 | 
| foo |  2 |  0  | 3     | 2012-05-11 10:02 | 
+------+-----------+------------+----------------------+------------------+ 

Así que algo como ...

SELECT 
    Item, {xyz} as 'Stock Up', {abc} as 'Stock Down', `Running Stock Total`, `Transaction Time` 
FROM 
    `StockTransactions` 
WHERE 
    `Item`='foo' 
HAVING 
    ('Stock Up'>0 or 'Stock Down'>0) 

se puede hacer esto?

+0

¿Cómo se diferencia cuando la acción subió y cuando la acción bajó? – JHS

+0

Al usar el "Total de material en ejecución" – Urbycoz

+0

Su sintaxis se parece a SQL Server, pero su pregunta se etiquetó con MySQL. ¿Qué estás usando? – eggyal

Respuesta

3
SELECT `Item`, 
     `Stock Up`, 
     `Stock Down`, 
     `Running Stock Total`, 
     `Transaction Time` 

FROM (
    SELECT `Item`, 
      GREATEST(`Running Stock Total` - @`last_total`, 0) AS `Stock Up`, 
      GREATEST(@`last_total` - `Running Stock Total`, 0) AS `Stock Down`, 
      `Running Stock Total`, 
      `Transaction Time`, 
      @`last_total` := `Running Stock Total` 
    FROM  `StockTransactions` JOIN (SELECT @`last_total` := 0) AS lt 
    WHERE `Item` = 'bar' 
    ORDER BY `Transaction Time` ASC 
) AS t 

ORDER BY `Transaction Time` DESC 

Véa en sqlfiddle. La consulta externa se puede omitir obviamente si está contento con que los resultados se ordenen en orden ascendente del tiempo de transacción y con la columna adicional last_total.

+1

La consulta externa no se puede omitir, porque es en la consulta externa donde las filas pueden (y deben) filtrarse en la condición ''Stock Up'> 0 o 'Stock Down'> 0' (que es requerida por la pregunta y que no estás haciendo). Aparte de eso, creo que tu solución debería funcionar. –

+0

@eggyal Esta es una solución excelente y elegante. ¡Gracias! – Urbycoz

+0

@AndriyM: Buen punto: había pasado por alto ese requisito. – eggyal

0

Una solución podría ser:

  1. Hacer un cursor para seleccionar cada fila a la vez
  2. Compruebe si el valor ha cambiado y si es así, inserte la información en una tabla #temp
  3. Seleccionar todo datos de la tabla #temp

En lugar de un cursor, puede usar un ciclo while si puede identificar secuencialmente todas las filas.

0

Intentaré algo así como establecer una variable que contenga el precio de la acción anterior. Primero, clasifique la tabla por ítem para que pueda manejar todos los datos de cada stock por sí mismo.

Entonces puede decir algo como int counter = 0; decimal startingPrice = 0; costo decimal = 0;

 var list = new List<Decimal>(); 
     Decimal[] positivePercentagesToTest = new Decimal[] { 1.02m, 1.03m, 1.04m, 1.10m, 100 }; 
     Decimal[] negativePercentagesToTest = new Decimal[] { 0.99m, 0.985m, 0.98m, 0.95m, 0.9m }; 

     for (int i = 0; i <= positivePercentagesToTest.Count() -1 ;i++) 
     { 
      foreach (var s in stocks) 
      { 
       //if(s.Ticker == "BAC") 
       { 
        if (counter == 0) 
        { 
         startingPrice = s.Open; 
        } 
        counter++; 

        var openPrice = s.Open; 

        if (openPrice > (startingPrice * positivePercentagesToTest[i]) || openPrice < (startingPrice * negativePercentagesToTest[i])) 
        { 
         //sell 
         //same as percentage gain 
         var percentage = openPrice/startingPrice - 1; 

         list.Add(Math.Round(percentage, 2)); 
         counter = 0; 
        } 

       } 

      } 

      var amount = list.Sum(); 
      var profitToAdd = new Profits(); 
      profitToAdd.Amount = amount; 

Código de C#. Si lo necesita en sql, hágamelo saber. Esta es solo la lógica que usaría.

+0

Me temo que lo necesito en sql. – Urbycoz

0

No conozco su sabor SQL, pero en Oracle hay LAG() y LEAD() funciones analíticas que le permiten acceder a valores de columna de la fila anterior o siguiente en el conjunto de resultados. Puede usar LAG() para ver la diferencia entre el resultado anterior y el actual y decidir si está activo o inactivo. ¿Hay algo similar en tu SQL?

+0

Estoy usando MySQL. No creas que tiene algo similar. – Urbycoz

1

Mi solución funciona según la suposición de que Transaction Time es único según Item.

Estoy simulando row_number() función analítica a través del ayudante de vista que creo:

CREATE VIEW running_stock AS 
SELECT s.item,s.running_total,s.transaction_dt, 
    (SELECT count(*) FROM stock WHERE item=s.item 
     AND transaction_dt <= s.transaction_dt) AS row_number 
    FROM stock s 
ORDER BY 1, 4; 

Después de la vista está en su lugar, puede obtener los resultados deseados con la siguiente consulta:

SELECT c.item AS "Item", 
    greatest(c.running_total - p.running_total, 0) AS "Stock Up", 
    greatest(p.running_total - c.running_total, 0) AS "Stock Down", 
    c.running_total AS "Running Total", 
    c.transaction_dt AS "Transaction Time" 
FROM running_stock c 
LEFT JOIN running_stock p ON c.item = p.item 
     AND p.row_number + 1 = c.row_number 
WHERE c.row_number > 1 
ORDER BY 1, 5; 

Usted puede jugar con esta consulta en el SQL Fiddle.

Cuestiones relacionadas