Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Serapis

#2461
Cita de: hecdoteam en 23 Mayo 2018, 06:03 AM
>:DQuisiera que alguien super inteligente me saque de la duda si esto es posible o no, no me den respuestas de lento pensar, haciendo comprobaciones con el listado de todos los numeros y comprobando si esta... es algo de tarea programacion 1 eh visto de todo y no encuentro nisiquiera una formula que pueda hacer sin ningun arreglo en java.
Ni en Java ni en ningún otro lenguaje.

Actualmente no existe ningún algoritmo en tiempo polinomial para resolver si un número dado es primo. Exige usar los primos menores que él.
Si no tiene divisores, es primo...
...luego, que calcules esos primos sobre la marcha o que uses una lista ya precalculada, solo sirve para acelerar la búsqueda.

La solución a ese problema pertenece al cuerpo teórico de las matemáticas.
Mi intuición me dice que sí que existe una función así, pero... de momento, es algo irresoluble.
#2462
jajaja... que bueno.
Si temes que tu pareja (o un conocido) suba una foto sin tu consentimiento, mejor sube tu mismo las 250 que tienes (a unos desconocidos). si no confías en tu pareja, porqué vas a confiar en unos desconocidos????. Absurdo.

Lo mejor es no hacerse nunca fotos salidas de tono y listo. Y si te las hiciste, elíminalas para siempre. Tu pareja ya te tiene 'en persona' no necesita tenerte en fotos.

Otro problema es que pasa con facebook y las colisiones... yo estoy seguro que si hasheao todas la imágenes de mis discos, posiblemente no haya colisión, pero con las fotos de cientos de millones de millones de personas, me temo que colisiones se van a dar sí o sí... con alguna frecuencia. Salvo que usen dos hashes distintos para una misma imagen.
#2463
Programación C/C++ / Re: Tiempo en aprender
23 Mayo 2018, 19:08 PM
El tiempo que se tarda en ir desde la Ciudad-A hasta la Ciudad-B, depende principlamente de dos factores:
1 - La distancia que las separa.
2 - La velocidad de recorrido.

En tu caso, ni sabemos la distancia que te separa del conocimiento de C++, ni la velocidad de tu aprendizaje, luego no hay más respuesta válida que la incertidumbre.
#2464
Citar"Yo repudio todas las sanciones que se pretenden contra la República Bolivariana de Venezuela, porque le hacen daño, generan sufrimiento, al pueblo de Venezuela", afirmó.
Que repudie... hasta que al final sea la gente (incluso cercana) la que le repudie a él.

La goma se puede estirar tanto como quieras, pero cuando se rompa, se acabó el juego, ya no habrá más estirarla.



...la verdad que tengo serías dudas de que nadie con sentido común haya decidido en Venezuela seguir apoyando a este tipo en las votaciones recientes, porque significa seguir pasando apuros,  innecesariamente, meramente por caprichos sobre ideales absurdos... por otro lado, es más probable que los chanchullos en las urnas estén a la orden del día, pero como no admite otro control que el suyo, pués los chanchullos se dan por ciertos, sí o sí.
#2465
Cita de: Darklexis312 en 22 Mayo 2018, 18:55 PM
Hola muchas gracias por responder a mis dudas fueron de mucha ayuda tus comentarios, probe lo que dijiste sobre mi problema número dos y así quedó mi programa ahora:

Ahora cuando elijo ingresar por ejemplo dos sueldos, ingreso el primer sueldo después me pregunta si quiero ingresar otro sueldo y cuando pulso s se sale del ciclo.


...
int main() {
int sueldo[100];
   char op;
   int i,j, D, arc, empleados=0;
   float promedio, suma=0;
   printf("\nCuantos sueldos desea ingresar?: ");
   scanf("%i", &D);
   if (D > 0 && D < 100) {
       do {
            ...
               
               
               printf("\nDesea introducir un sueldo? [s/n]: ");
               fflush(stdin);
               while (getchar() != '\n');
              scanf("%c", &op);
               if (op == 'n' || op == 'N') {
                   break;
                   }
                }
           }   while (D<1||D>99);
       system("cls");
...


Pués para haber leido mi respuesta, no veo que hayas cambiado significativamente el código, especialmente lo que te remarcaba aquí, sigue estando...
Cita de: NEBIRE en 22 Mayo 2018, 16:54 PM
... solicitar al comienzo cuantos sueldos se desean ingresar ... Pero en esete caso, sobra volver a preguntar si quiere señalar otro sueldo dentro de ese bucle... esto ya se preguntó antes.

Elige una de las  dos opciones... O preguntas al principio, cuantos (y ya nunca más), o preguntas sobre la marcha ¿otro sueldo? y en consonancia los bucles son diferentes...

nada, nada... revisando más a fondo el código, ahora veo bucles por todas partes....
Para preguntar los sueldos solo necesitas un único bucle...punto.
Luego podrás necesitar alguno más para hacer los cálculos, pero no para pedir sueldos...



Intenta entenderlo...

Si de entrada preguntas a un jefe en la oficina: Cuantos empleados tienes a sueldo? ... Si responde por ejemplo 23, tu bucle deberá ser de 23 y será exclusivamente para pedir YA, las cantidades, no se puede pedir (al jefe) más nada en ese bucle. La unica forma de salir del bucle debe ser completar el valor de los 23 sueldos... Sí o Sí... (esta es la propuesta: empezar preguntando cuantos).

Hacer
   D = Preguntar cuantos sueldos quieres tratar?
   Si D está en el rango 1-99
       bucle para i desde 0 a D-1
            sueldo(i) = Preguntar a cuanto asciende el sueldo del empleado 'i'
            // algunas operaciones de cáclulo se pueden hacer directamente dentro del propio bucle
           // por ejemplo, el total...
           total += sueldo(i)
           ...etc...
       repetir
       // y otras operaciones (como por ejemplo si se pidiera ordenar los sueldos), se deben hacer fuera dle bucle.
       // por ejemplo el promedio.
       Promedio = (Total /D)
       ...etc...
   Sino
       mensaje "error solo se permite señalar entre 1 y 99 sueldos. Vuelva a señalar un valor correcto."
   fin si
Repetir mientras ((D < 1) ó (D>99))

Hay dos bucles, pero el externo (el que aparece primero) sirve exclusivamente para asegurarse que el jefe responde un valor de empleados entre 1 y 99... una vez responde bien, ese bucle pierde su efecto, de hecho si empieza dando un valor adecuado, ese bucle se ejecuta una sola vez.

Reformulo dichos bucles para que lo veas más claro:

// primer bucle: Aqui te preguntaré hasta que me dés un valor correcto...
   // Tantas veces dé un valor incorrecto, tantas veces preguntará...
Hacer
   D = Preguntar cuantos sueldos quieres tratar (elija un valor entre 1 y 99)?
Repetir mientras ((D < 1) ó (D>99))

// segundo bucle aquí solo pregunto el valor de los sueldos y NO pregunto nada más...
   // la cantidad del bucle es ya conocida: "D veces" (pero empezando desde 0, acaba en 1 menos).
bucle para i desde 0 a D-1
   sueldo(i) = Preguntar a cuanto asciende el sueldo del empleado 'i'            
   total += sueldo(i)    
   ...etc...      
repetir
 
Promedio = (Total /D)
...etc...



En cambio imagina que no está el jefe, te encuentras en la cafetería a los empleados, tu pregunta será entonces: Hay algún empleado aqui? y si uno levanta la mano y dice "si, yo", entonces le preguntas luego (y cuál es tu sueldo?) ... en esete caso el bucle acaba cuando recibes una respuesta de 'no', ya no hay más empleados... y por tanto ya se sale del bucle... el bucle a priori desconocemos cuantas veces se ejecutará, por eso el bucle for, no se aplica en este caso. Y por supuesto con cada respuesta aquí, D aumenta en 1, inicialmente era 0, y si llegara a 99, también se sale sin preguntar a nadie más...
es más como queremos que sea mayor que 0, inicialmente no empezamos preguntando si alguien más es empleado, inicialmente preguntamos el sueldo para asegurarnos que al menos uno nos dé su sueldo, si inicialmente preguntas si hau algún empleado y te dicen que no... saldrías del bucle, pero... al salir del bucle así, tienes 0 empleados... cosa inadmisible, según los requisitos... (esta es la propuesta: preguntar sobre la marcha).

Limpiando el pseudocodigo de comentarios extras, para verlo más nítido.

   D = 0
   i = 0
   // Este bucle se repetirá mientras se indicque 'si' y no se alcance 99 empleados
   Hacer        // la condición se hace alfinal, para asegurarnos que al menos tengamos 1 sueldo.
       sueldo(i) = Preguntar a cuanto asciende el sueldo del empleado 'i'
       total += sueldo(i)
       D += 1  //sumamos un empleado que ACABA de señalar su sueldo.

       massueldos = Preguntar: quiere señalar el sueldo de otro empleado (S/N)
   repetir mientras ((D < 99) y (massueldos = "S" ó "s"))
 
   Promedio = (Total /D)
   ... etc...



Olvídate de la programación por un momento, intenta llevarlo al terreno 'personal', imagina que físicamente haces la pregunta a una o varias personas... mantén ese diálogo interno, y mira si no te resulta absurdo... lo que has escrito... ...pero intenta imaginártelo físicamente, para entenderlo. la programación no es redactar sin sentido y a ver si sale... es copia fidedigna de la realidad. Luego piensa como sucede en la vida real.
Cuando entiendas perfectamente esto, la programación será como beber cerveza, ningún misterio... aunque puedes acabar 'borracho'...  :laugh: :laugh: :laugh:

Hale, a ver si ahora lo pillas...  :rolleyes: :rolleyes:
#2466
Citar1) Si por ejemplo elegí ingresar dos sueldos y solo ingreso uno, y elijo que no
quiero ingresar otro sueldo me imprime el sueldo ingresado y después números al
azar como si hubiera ingresado un segundo sueldo, como puedo arreglar eso?
A - En ciertos lenguajes, al declarar un tipo de dato, es obligado inicializarlo al valor deseado. Si no se hace e valor que tienen es lo que hubiera previamente en esa posición de memoria.
B - En otros lenguajes, al declarar un tipo de datos, se inicializa al valor por defecto (0 en caso de los números).
El lenguaje C entra en la categoría A. Así que o bien, antes de nada pones a 0 todo el array sueldos, o bien antes de solicitar que se ingrese el sueldo, lo pones a 0, o bien no importa, porque si introduce el usuario un valor, ya cambia el que hubiera previo. En este último caso, todavía tendrán valores 'sucios' los sueldos no asignados desde D hasta 99.... pero te da igual, si solo vas a contabilidar y operar con los 'D' sueldos.

Citar
2) Si por ejemplo elijo de nuevo ingresar 2 sueldos, me pide que ingrese el sueldo
del empleado 1 después me pregunta que si quiero ingresar otro sueldo elijo que
si, ingreso el sueldo del empleado 2 y despues me vuelve a preguntar si quiero
ingresar otro sueldo y no quiero que haga eso el programa quiero que imprima
directamente después de ingresar el segundo sueldo.
Esto es cosa de tu diseño.
- No es mala estrategia solicitar al comienzo cuantos sueldos se desean ingresar, si elige 15... pués se solicitan 15. Pero en esete caso, sobra volver a preguntar si quiere señalar otro sueldo dentro de ese bucle... esto ya se preguntó antes.
- La otra solución es partir de la incertidumbre e ir preguntando en el bucle... en ese caso, la pregunta previa al bucle sobra y por tanto las comprobaciones deben hacerse in situ dentro del bucle al final.

Preguntar al comienzo:

Hacer
   D = Preguntar cuantos sueldos quieres tratar?
   Si D está en el rango 1-99
       bucle para i desde 0 a D-1
            sueldo(i) = Preguntar a cuanto asciende el sueldo del empleado 'i'
            // algunas operaciones de cáclulo se pueden hacer directamente dentro del propio bucle
           // por ejemplo, el total...
           total += sueldo(i)
           ...etc...
       repetir
       // y otras operaciones (como por ejemplo si se pidiera ordenar los sueldos), se deben hacer fuera dle bucle.
       // por ejemplo el promedio.
       Promedio = (Total /D)
       ...etc...
   Sino
       mensaje "error solo se permite señalar entre 1 y 99 sueldos. Vuelva a señalar un valor correcto."
   fin si
Repetir mientras ((D < 1) ó (D>99))


Preguntar sobre la marcha:

   D = 0
   i = 0
   Hacer        
       sueldo(i) = Preguntar a cuanto asciende el sueldo del empleado 'i'
       // algunas operaciones de cáclulo se pueden hacer directamente dentro del propio bucle
       // por ejemplo, el total...
       total += sueldo(i)
       ...etc...
       D += 1  //sumamos un empleado que señala su sueldo.

       massueldos = Preguntar: quiere selar el sueldo de otro empleado (S/N)
   repetir mientras ((D < 99) y (massueldos = "S" ó "s"))
   // y otras operaciones (como por ejemplo si se pidiera ordenar los sueldos), se deben hacer fuera dle bucle.
   // por ejemplo el promedio.
   Promedio = (Total /D)
   ... etc...

Tu decies que modelo usar, pero sé consecuente con el modelo elegido... no puedes mezclar ambos.

Citar
3) Como puedo saber cuantos empleados tienen un sueldo superior al promedio?
Ya te he selado claramente que algunas operaciones pueden hacerse dentro del bucle, pero otras no.
El promedio no puede calcularse hasta que el 'último empleado' haya dejado constancia de sus sueldo, porque el promedido depende del total, y este solo se sabe al final.
Luego exige un nuevo bucle donde recorras desde 0 hasta D-1, comparando:
    si suedlo(i) > promedio luego superior +=1
#2467
Mathematica
...y a diferencia de Derive, sigue en activo...

En algún disco tengo una versión vieja del 2002-2003 o así... si no logras encontrar una más actual, avisa.

p.d.: Olvidaba ponerte enlace:
http://www.wolfram.com/mathematica/

Mira abajo (en la página) donde pone: Cobertura y accede al área de tu interés...

Para ver lo nuevo en la versión 11
http://www.wolfram.com/mathematica/new-in-11/
#2468
Tienes varios errores.

El primordial es la sintaxis: Debes poner las llaves y los finales de sentencia donde corresponden, sin omitir ninguno, no son opcionales...

Otro error (éste semántico)...  mirando por ejemplo la función Buscar... 'p' siempre es nulo, nunca se le asigna nada, incluso aunque se encuentre la clave buscada.
Del mismo estilo es que aunque (ésta) la función devuelva algo, luego 'nadie' está allí para recoger la 'pelota' que desde aquí se envía...
En la segunda función (mostrar) pasas el nodo por referencia, pero aquí (buscar) por valor, podría por ello parecer... pero no puede ser una omisión a causa de esto, ya que declaras la función como 'no vacante' (no es void) y explícitamente 'devuelves' p.

Otro medio error, menos importante es que en la llamada inicial no se verifica si la clave recibida es nula. Asi en 'BuscarPelicula', si comprueba ese parámetro, no s epierde tiempo luego en ser revisado más adelante, ni ejecuta más acciones innecesarias si ya desde el principio resulta innecesario. Imagina que vas a una ferretería a comprar un pegamento, el tipo no vende pegamento, pero se larga al almacen a buscar, para después de media decirte que 'aquí no vendemos pegamento', acaso no hubieras preferido que empezara por ahí???.

Corrige todo lo previo y probableente los cambios, ya te lo dejen más libre de errores...

Luego donde dices: "En este caso me da el mismo error pero en "nodo->info << endl"", sintácticamente es correcto, luego si existe un error será semántico. Como por ejemplo: ¿Qué tipo de datos aloja nodo.info? o uno más prosaico: qué crees que debe mostrarse si ese nodo es nulo y no existe pero aún así se insiste en acceder a uno de sus miembros?.

Nota que no es lo mismo un nodo vacío que un nodo nulo. Un nodo vacío, es un nodo creado, pero al que (todavía) no se le han introducido datos... luego permite acceder a sus miembros y mostrar lo que tenga (por ejemplo una cadena vacía), en cambio un nodo nulo, es un nodo inexistente al momento, no se ha alogado espacio en memoria para él.
#2469
No, yo no me enojo fácilmente... lo que pasa es que a veces al hablar, puedo parecer brusco y de ahí habrá quien asuma enojo...

Más arriba te ponía un ejemplo (con código y todo), con la intención de explicarte que aunque hay múltiples ítems en principio ídénticos, ninguno caía en otra 'caja' que la suya propia, precisamente para ilustrar que lo que lo hace posible es elegir una clave única para esa 'caja'...
...en el ejemplo, la clave se formaba con "año" + los 4 digitos del año.

De igual modo debes proceder tú... Para rama principal se le debe asignar una clave única. Y luego todos los elementos bajo esa rama, deben hacer alusión a esa clave.
En realidad es algo que ya debería venir desde diseño en la propia BD. Si no es así, el código para delimitar correctamente cada caso, puede ser tortuoso, porque tendrás que verificar muchos otros factores (posiblemente no disponibles en los datos rescatados), que supondrá mayor sobrecarga, aún suponiendo que logre salir bien... o directamente no ser posible por no disponer de los datos suficientes para delimitarlo.

He abierto tu base de datos, pero hay bastantes tablas y no me apetece perder tiempo mirando la relación entre ellas, si lo tienes preferiría que pusieras un diagrama (incluso aunque sea dibujado a mano), donde se vea la relación entre todas ellas... tampoco es preciso que sea un diagrama de toda la base de datos, basta que te ciñas por ejemplo a 'cotizaciones' y muestres las tablas implicadas con esta, los campos que tiene cada una y como se relacionan los campos (los que se relacionen) de una con las otras... Después es solo extender el concepto al resto de casos.





La forma óptima pasa por un diseño adecuado de la base de datos...
Realmente lo que he visto de tu BD, dista mucho, así que intento hacerte una explicación algo en detalle pero sin profundizar (daría para un libro).

Sea una tabla llamada ventas, con estos campos:
- IdVenta: -> único, numérico, autoincrementable, "primary key", otras tablas se relacionan con esta clave.
- IdArticulo: -> Foreign key, relacionado con la tabla artículos. Realmente este campo puede ser una lista de artículos (cada compra no es de un solo artículo) en cuyo caso no debe aparecer como tal, si no como un método "GetArticulosPorVenta(IdVenta)"
- IdComprador: -> Foreign key, relacionado con la tabla artículos.
- IdVendedor: ->  Foreign key, relacionado con la tabla artículos.
- IdEnvio: -> Foreignkey, relacionado con la tabla envios. Este dato se rellena cuando el vendedor relice el envío.
- IdMetodoEnvio: -> Foreign key, relacionado ocn una tabla ServiciosDeEnvio, es un valor elegible por el comprador, de una enumeración... esto es muy dependiente de las zonas geográficas y los sevicios que allí se den. pero generalmente existirá algún tipo de prioridad (estandar, urgente y muy urgente), etc.. Este dato se rellena cuando el comprador elige un método de envío entre los disponibles. Al final hablo de la tabla Mensajeros y ServiciosDeEnvio.
- EnvioConjunto: En esta venta varios artículos se envían juntos en un mismo paquete. (esto se relaciona con IdArticulo, más abajo hablo sobre esto)
- FechaVenta: -> datetime, tomada con la función 'now', en el momento de validar la compra.
- FechaEntrega: -> datetime, fecha prevista de entrega, aproximada... posiblemente sea la suma de la fecha de compra o más claramente de la fecha de verificación del cobro, + TiempoLogistica (dependiente del artículo, tamaño, existencias, origen) y destino del comprador (si vive en la ciudad, en el país, o en el extrajero) y posiblemente del método de envío elegido. Este dato se rellena automáticamente cuando se eleige l método de envío...
- Estado: -> valor de enumeracion: problema, comprado, pagado, procesando, enviado, recibido, eliminado (retirado a una base de datos de backup, cuando ya tiene una antigüedad de x semanas/meses tras ser recibido). Problema es el resto de estados pero en valor negativo, indica que en ese estado positivo se registró un problema, así se sabe que es un problema y donde recáe el problema.

En tu Bd, para esta tabla, usas ncli, usa mejor IdCliente para señalar que es una clave única (Id)... y usa el nombre completo, IdCliente, IdComprador, no IdCli, ni IdC... no se ahorra nada por omitir 8 caracteres en el nombre de un campo.

A tu tabla le falta (como mínimo) el IdArticulo...(pero esto tiene miga, me extiendo más abajo, primero por pasos) cada venta es única, pero diferentes ventas pueden tener un mismo artículo...
Una posible explicación es que tienes una tabla llamada Ventas_Detalles, bien puedes trasladar ahí los detalles de esta tabla, pero en ese caso, en esta tabla debe haber unica y exclusivamente el IdVenta y pocos campos más (también Ids)... es decir esta tabla sería un 'array' un índice donde buscar la venta y con ella ir a la tabla detalles... sin embargo lo veo redundante. porque en la tabla detalles, no va a haber repetida ningún idVenta, luego aquella es un clon de esta, pero disperasando unos datos en una y otros en otra...

Una misma venta puede contener varios artículos, por lo que en realidad, es mjor opción eliminar IdArticulo de la tabla ventas, pero disponer de un método apuntando a otra tabla... ahí si podría llamarse VentaDetalles, pero para nada los campos que tu tienes... y considerar que cada venta tiene detalles (como mínimo un artículo comprado) y para conocer los artículos comprados se debe consultar dicha tabla: "select IdArticulo from VentaDetalles where idVenta = EstaVenta" (Ventas.IdVenta: aquí se pasa el idVenta por el que estás interesado), esto devuelve todos los registros de artículos asociados a una venta específica, artículos que luego se colocan como hijos de la venta en el treeview.


Tabla VentaDetalles:
Cada registro de compone de dos referencias. Una al artículo y otra  a la venta. De esto modo multiples artículos comprados apuntarán a la misma venta.
- IdArticulo: foreign key, se relaciona con un único artículo.
- IdVenta: foregin key, relaciona a este artículo con una compra específica.
opcional - IdVendedor: foreign key (abajo del todo después del pseudocódigo comento esta opción)

La otra opción es más cara y supone un mal planteamiento de la base de datos, ya que exige que si se compran varios artículos, exista un registro de compra por cada artículo... Es mla planteamiento por:
- De entrada exige sobrecarga de memoria, la base de datos crece, una compra elegante solo requiere un registro de venta + 2 ids por cada artículo comprado, frente a tantos registro de venta como articulos comprados en una sola venta.
- Como cada venta, tiene su primarykey, esta resulta inútil para relacionar todos los artículos comprados con una sola venta (que es lo que te pasa). Supone entonces que al comprar debes crear una referencia única para cada venta (que es justamente lo que es un primary key, que se crea sola y de la que te desentiendes, pero aquí por tu solución te la debes currar tú), y en cada registro de venta (para una misma compra) debe constar esa referencia de venta...
- Supone además crear más métodos... para consultas y actualizaciones.
- No existe una tabla donde consten todas esas 'referencias únicas, sino que resulta de 'explorar' intensivamente dicha tabla 'ventas' (intensivamente=sobrecarga inútil).




Entonces la existencia de la tabla Ventas y los campos declarados sugiere que además deben existir las siguientes tablas (más las derivadas de esas):
Articulos, Compradores (clientes), Compras, Vendedores, Almacen, Pedidos, Mensajeros, ServicioDeEnvio, Envios, Imagenes...


La tabla articulo (producto):
Breve descripción: Sobre ella recáe el añadir o eliminar artículos (siponibles a la venta), y actualizaciones: modificar precio, descripción,  nombre imagen. Se relaciona además de con: Ventas, Clientes y Vendedores con Almacen y Pedidos.
Respecto de pedidos, hace falta saber si los artículos son todos de un solo vendedor o cada vendedor expone sus propios artículos (asumo esto último si existen IdVendedor, es que hay más de uno), es decir que no es para empresa que vende si no para una empresa que gestiona compra-ventas, ellos mismos solo son mediadores y no venden artículos propios. Esto implica que esta tabla puede ser muy diferente según el caso... haré una somera descruipción de cada caso aparte:
Si hay multiples vendedores, la tabla almacén, Pedidos y otras sobran, ya que será el propio vendedor el encargado de tales gestiones y escapa, aquí todavía se podrá mantener la tabla envíos, donde el comprador indique fecha de pago (si no es inmediato y recibido cuando llegue a su casa el paquete, y el vendedor indique cobrado, enviado... aunque estos estados deben ser opcionales, porque unos y otros suelen olvidar actualizar tales datos.


Tabla Articulo: Vendedor Absoluto: por ejemplo una ferretería, un supermercado.
- IdArticulo: -> único, numerico, autoincrementable, primary key,
- IdImagen: -> foreignKey --- se relaciona con la tabla Imagenes. Un valor 0 indica que no posee imagen asociada al artículo.
- Nombre: -> texto, 64caracteres máximo (aprox.). Nombre simple que el cliente verá como título del artículo.
- Referencia: ref + hash del nombre + IdArticulo , ejemplo:  refAD34B2-00345. Este se recalcula solo cuando cambia el nombre. Y solo sirve para ventas futuras, para las pasadas ya no importa.
- Descripcion: --> Texto más largo y más detallado, que descibra el producto.
- TiempoDeManipulación: -> numerico byte, indica el tiempo aproximado (en días) que se tarda en envolver y enviar dicho artículo. No es lo mismo un reloj, que un armario de 4 puertas. En caso de un supermercado, o una ferretería esto es inmediato, se lo lleva el propio comprador, luego este campo sobraría.
- Peso: -> numerico, entero . peso aprox en decimas de kg. es decir algo de valor 1, señala que psa 100 gramos, algo de valor 10 pesa 1kg. (para evitar operar con números reales), si requieres dos decimales, es volver a plicar lo mismo.
- Dimensiones: -> 20 caracteres en la forma xxx'xx-yyy'yy-zzz'zz  largoXanchoXalto en cm. con 2 decimales. Un comprador querrá saber las medidas de ciertos artículos. si empieza por un valor que no es dígito, se considera que no se proporciona medidas, no uses espacios al caso, relena con ceros, ejemplo: 001'23-030'00-102'40.
- Existencias: -> numérico Cantidad restante en stock. ---> Debe relacionarse con tabla Almacen
- AlarmaExistencias: -> numérico, Cuando se compra un artículo, existencias se reduce en 1 8la cantidad comprada), y se verifica si es menor o igual que este campo, si es así, dispara un evento a "Pedidos".


Tabla Articulo: Múltiples Vendedores: La empresa es un intermediario entre el comprador y vendendor (tipo eBay).
Como decía más arriba para la descripción de artículos, si cada artículo es provisto por un vendedor concreto, forzosamente es obligado que esta tabla incluya unos campos y no requiere otros. Del mismo modo unos campos los podrá modificar el vendedor otros son automáticos (como los ids) y según la necesidad de destino, otros pueden variar...
- IdVendedor: -> foreign key, a fin de que un vendedor pueda tener acceso a su artículo en venta y hacer las modificaciones que precise.
- IdArticulo: -> único, numerico, autoincrementable, primary key,
- IdImagen: -> foreignKey --- se relaciona con la tabla Imagenes. Un valor 0 indica que no posee imagen asociada al artículo.
- Nombre: -> texto, 64caracteres máximo (aprox.). Nombre simple que el cliente verá como título del artículo.
- Referencia: ref + hash del nombre + IdArticulo , ejemplo:  refAD34B2-00345. Este se recalcula solo cuando cambia el nombre. Y solo sirve para ventas futuras, para las pasadas ya no importa.
- Descripcion: --> Texto más largo y más detallado, que descibra el producto. Un libro puede llevar el nombre de autores o ISBN, en cambo un pantalón puede señalr si es para señora y la talla.
- TiempoDeManipulación: -> numerico byte, indica el tiempo aproximado (en días) que el vendedor señala tardar en envolver y enviar dicho artículo. Este tiempo se supone que es añadido a la fecha de verificación del cobro.
- Peso: -> numerico, entero . peso aprox en decimas de kg. es decir algo de valor 1, señala que psa 100 gramos, algo de valor 10 pesa 1kg. (para evitar operar con números reales), si requieres dos decimales, es volver a plicar lo mismo.
- Dimensiones: -> 20 caracteres en la forma xxx'xx-yyy'yy-zzz'zz  largoXanchoXalto en cm. con 2 decimales. Un comprador querrá saber las medidas de ciertos artículos. si empieza por un valor que no es dígito, se considera que no se proporciona medidas, no uses espacios al caso, relena con ceros, ejemplo: 001'23-030'00-102'40.
- Existencias: -> numérico Si el vendedor dispone de más de 1 igual a la venta, en otro caso vale 1. Esto no requiere almacén Debe relacionarse con tabla Almacen
- Otros campos que pudieren ser importantes según el cliente del programa.


Tabla Compras:
Esta tabla tiene el mismo propósito para los Compradores que para los Vendedores la tabla Ventas.
En realidad bien diseñado, Ni Ventas ni Compras deben existir, si no una llamada Transacciones donde el vendedor hace consultas de sus Ventas (esto es, ventas sería una clase con varios métodos, lo mismo que compras, que realizan consultas a la tabla transacciones, una spreguntando con IdVendedor y otros con el IdComprador).
Que se le llame tblTransacciones a la tabla, no cambia más que el nombre, los campos vienen siendo los mismos, solo lo aleja de la idea de 'pertenencia' o asociación a 'vendedores'.


Tabla Imagenes:
Contiene el id de cada imagen y la ruta donde localizarla.
Hay quien guarda la imagen en la base de datos, pero eso hace una base de datos gigante y la expone a fallos y problemas de rendimiento. Por ejemplo cuando se debe restructurar una base de datos, mover imágenes (registros conteniendo imágenes) es pesado...
Solo tiene dos ventajas guardar imágenes en la BD: resulta tan infranqueable como la propia BD, la posibilidad de extravío se limita al extravío de la propia BD. En su contra lo mismo, si están en la BD y esta revienta, se piuerden todas, si están en ficheros sueltos en una carpeta, se perderá la que se pierda el resto se mantiene.
Aún así si uno decide guardarimágenes en una BD, sugiero que es aBD, solo aloje imágenes y nada más...
- IdImagen:  -> único, numerico, autoincrementable, primary key, Una imagen inexistente debe tener id=0, una imagen ilocalizable se debe devolver mediante un método que al final entregue -Id . Así cuando se localiza una imagen si se devuelve un valor menor que 1, implica que (0) ó no tiene (-0) ó que la imagen no está en la ruta esperada, fue eliminada, renombrada, etc...
- Ruta: -> texto, 512 caracteres (los 248 para la ruta + los 260 para el fichero).. seguramente no se usen... una forma de dejarlo más corto, es dejar rutas relativas, para el fichero, es decir la carpeta es fija y conocida en la instalación, por tanto basta guardar el nombre d ela imagen, y al caso entonces se puede crear un hash para la imagen como nombre basado en el IdArticulo y Nombre del artículo, + la extnsión de la imagen, con lo que se reduce a apenas 32-40 caracteres: ..\Imagenes\articulos\*.*

Las tablas Compradores, Vendedores, Mensajeros vienen a ser casi idénticas, solo cambia su nombre. Y la tabla que s eles asocia: A Vendedores con Ventas, a Compradores con Compras, a Mensajeros con Envios  y a los previos también con Envios indirectamente a traves de compras o ventas.


Otras tablas:
Almacen: Stocks de entrada.
Pedidos: Stocks de compra.
Mensajeros: Datos de empresas de enviós. (es idéntico a compradores y vendedores)
ServiciosDeEnvio:
- IdModeloEnvio: sería su principal campo, donde se relaciona la empresa IdMensajero con un tipo particular de envio..
- Prioridad: estandar, urgente, muy urgente,
- Lejania: local, nacional, internacional, etc...
- MedidasMaximas (como campo más arriba de 20 caracteres)
- PesoMaximo: (como campo más arriba, para evitar decimales)
- Precio: Lo que cuesta este servicio si cae dentro de las exigencias.
- Sobrecoste1:  Precio extra por algún detalle, por ejemplo si sobrepasa de 12, pero no llega a 20, x por cada kilo o fracción extra. (el 1 es porque puede haber más sobrecostes).

En realidad el diseño final, depende mucho de los requisitos del que reclama el programa (al margen de la propia especificación), unos te dan rienda suelta, y otros reclaman cosas muy específicas... y a veces absurdas.



Y bueno, si esto lo tuvieras más o menos así... teniendo perfectamente relacionado cada cosa con su Ids, se puede usar para rescatar de la BD, los registros asociados.
Entonces, con el diseño mostrado para la clase ventas, por ejemplo podrías tomar cada registro de venta de un vendedor y luego buscar los artículos de cada venta...

Evidentemente la vista del treeview, contendrá lo que se quiera consultar, pero se debe ser coherente... en el ejemplo se mstraría como raíz los datos del vendedor, como hijo de este ítem cada una de las ventas, y bajo cada venta cada uno de los artículos de dicha venta.
(podría reducirse desde todas a solo las que haya a partir de 'x' fecha, o solo las 'y' últimas)...

' se omite cualquier tratamiento posible de error, solo pretende ser ilustrativo de la forma correcta de proceder
Funcion VistaVendedorTodasSusVentas( numerico esteVendedor, string conectionString)
  Resulset: rsVendedor, rsVentas, rsArticulo

  Vaciar Treeview
  AbrirBD(conectionString)

   rsVendedor = Select From tblVendedores where IdVendedor = esteVendedor
   Añadir al Treeview como raíz el registro IdVendedor

   rsVentas = "Select all from Ventas where IdVendedor = EstevendedorQueConsulta", y luego en un bucle
   Por cada registro de este rsVentas
       Añadir al treeview esta venta con clave IdVenta, bajo raiz. ('strinnizada', añadiendo algún caracter para que no empiece por dígito, por ejemplo el nombre del vendedor, o simplemente key = "v" & IdVenta
       rsArticulos = "select IdArticulo from VentaDetalles where idVenta = EstaVenta"
       For cada registro en rsArticulos
           Articulo = "Select * From tblArticulos where IdArticulo = registro"
           añadir al treeview como hijo de IdVenta, los detalles del artículo que interesen..
       siguiente
   Siguiente
   
   cerrar BD
Fin funcion

Puede que a primera vista te parezca mucha sobrecarga tantas consultas, pero se limita a lo preciso en cada caso, no a obtener un tocho de regstros que luego no se requieran, o no se correspondan, como resultado es más eficiente, son llamadas breves y rápidas, porque son muy acotadas.

Si Access no se comportara bien (no debería ser problema con las versiones actuales que están muy optimizadas, otro cantar sería versiones de los 90), en esos casos quizás convenga añadir a la tabla tblVentaDetalles el campo IdVendedor, y así se podrían rescatar todos de la BD, de una sola vez, a la entrada de la función (en vez de en el bucle), y en el bucle luego revisar cuales correponde al caso. para aligerar esto, con cada añadido al treeview, sería acorde ir eliminado del resulset los registros ya metidos, así la búsqeuda sería más corta cada vez en el bucle... es decir estamos remplazando la sobrecarga en el servidor (donde consta la BD), por sobrecarga en el entorno de la vista (el equipo del cliente)...

Otra opción a considerar en el ejemplo, sería mostrar el vendedor en raíz, y luego bajo el las ventas... y solo cuando el usuario pulse en dicha venta es cuando se consulta los artículos para dicha venta y se muestra en otra ventanita aparte (o en la misma ventana bajo el treeview principal, otro treeview, o un listview a la derecha, etc..).
Esto es aún más acertado, porque aligera aún más la BD de carga de trabajo, solo se reclamarán los artículos de aquella venta para la que el usuario quiera ver los detalles.


Y bueno ya sale un mensaje largo así que corto...
#2470
Pero eso es ya un problema d elos detalles de la base de datos.

En realidad, yo he puesto como clave:
Key = RST!NOMBRE_CLI & CStr(RST!IDCoti)
...pero en realidad, yo he usado un criterio arbitrario, tú eres quien tiene los detalles de la base de datos.
La cuestión es que debes usar como clave algo único, que no esté replicado por otro lado... yo he partido del supuesto que IdCoti, es una clave única (por ejemplo) respecto de una transacción para un cliente, es decir que no puede estar asociado a otros clientes, ni a otras transacciones.

La forma de arreglarlo, es tener coherencia en la BD, para tener campos únicos de modo que no pueda existir más asociación que (por ejemplo) el par formado por NombreCli + IdCoti... y en consonacia usar la clave adecuada al caso.
Dicho de otro modo, si tienes un campo "primary key" para cada 'grupo', ahí tienes la segunda parte de la clave, junto con el nombre del grupo, o simplemente "g" + rst.Id (que se declaró primaryKey).

Y por lo mismo es tu responsabilidad asegurarse que si en el mismo treeview debes mostrar diferentes tablas al mismo tiempo sus primary key, deben ir precedidas por algún identificador distinto en cada caso... precisamente para que no cuelen agrupaciones foráneas...

...en definitiva elige como clave algo único, exclusivo para cada agrupación, para que solo sus artículo y ningún otro puedan asociarse a esa clave... y nada más pueda colarse bajo él... si no has diseñado adecuadamente la BD, quizás tengas que reestructurarla...