¿Por qué la gente recomienda no usar el nombre "Id" para una columna de identidad?

68

Me enseñaron a no usar el nombre Idpara la columna de identidad de mis tablas, pero últimamente lo he estado usando de todos modos porque es simple, breve y muy descriptivo sobre lo que realmente son los datos.

He visto a personas sugerir prefijos Idcon el nombre de la tabla, pero esto parece hacer más trabajo para la persona que escribe las consultas SQL (o el programador si está utilizando un ORM como Entity Framework), particularmente en nombres de tabla más largos como CustomerProductIdoAgencyGroupAssignementId

Un proveedor externo que contratamos para crear algo para nosotros en realidad nombró todas sus columnas de identidad Identsolo para evitar su uso Id. Al principio pensé que lo hicieron porque Idera una palabra clave, pero cuando lo examiné, descubrí que Idno es una palabra clave en SQL Server 2005, que es lo que estamos usando.

Entonces, ¿por qué la gente recomienda no usar el nombre Idpara una columna de identidad?

Editar: para aclarar, no estoy preguntando qué convención de nomenclatura usar, o argumentos para usar una convención de nomenclatura sobre la otra. Solo quiero saber por qué se recomienda no usar Idel nombre de la columna de identidad.

Soy un programador único, no un dba, y para mí la base de datos es solo un lugar para almacenar mis datos. Como generalmente construyo aplicaciones pequeñas y normalmente uso un ORM para el acceso a datos, es mucho más fácil trabajar con un nombre de campo común para el campo de identidad. Quiero saber qué me estoy perdiendo al hacer esto, y si hay alguna buena razón para no hacerlo.

Rachel
fuente
10
BF bunfight aquí ya: programmers.stackexchange.com/q/114728/5905 Varios de nosotros (léase: yo)
fuimos
¿Existe realmente una regla contra el uso de "id" como el nombre de la columna de identidad? ActiveRecord, el ORM estándar para Ruby on Rails, hace exactamente eso por convención. ar.rubyonrails.org
200_success
1
@ 200_success En el nivel de la base de datos, sí. Este es el sitio de la base de datos, no el sitio ORM;)
JNK
2
Además, para SQL Server específicamente, consulte dba.stackexchange.com/questions/124655/… y, más específicamente, connect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

Respuestas:

46

El prefijo del nombre de la tabla tiene muy buenas razones.

Considerar:

TableA (id int identity, stringdata varchar(max))

TableB (id int identity, stringdata varchar(max))

Queremos DELETEpartir de TableAregistros que existen en ambas tablas. Muy fácil, solo haremos un INNER JOIN:

DELETE a
FROM 
  TableA A
INNER JOIN 
  TableB B
    ON b.id = B.id

... y acabamos con todo TableA. Inadvertidamente comparamos la ID de B consigo mismo: cada registro coincidía y todos los registros se eliminaban.

Si los campos hubieran sido nombrados TableAIdy TableBIdesto sería imposible ( Invalid field name TableAid in TableB).

Personalmente, no tengo ningún problema con el uso del nombre iden una tabla, pero en realidad es una mejor práctica ponerle un prefacio al nombre de la tabla (o el nombre de la entidad, si TableAfuera gente, entonces PeopleIdtambién funcionaría bien) para evitar comparar accidentalmente el campo incorrecto y soplar Algo ahi.

Esto también hace que sea muy obvio de dónde provienen los campos en consultas largas con muchos JOINs.

JNK
fuente
10
Entonces, ¿es básicamente una convención de nombres para protegerse contra errores? Creo que usar begin transactiony commit transactionsería una mejor práctica que usar (imo) un esquema de nombres más desagradable
Rachel
13
@Rachel: es por 1. claridad 2. evitar alias de columna innecesarios 3. permitir UNIRSE ... USAR 4. molestar a los monos PHP que trabajan en objetos individuales, no en conjuntos
gbn
44
@Rachel Si no notó el error al escribir la consulta, y justo antes de ejecutarla, es poco probable que lo note antes de comprometerse. Esto sucede, ¿por qué hacerlo más probable?
Andy
77
@Andy Siempre hago un SELECTpara encontrar mis registros antes de ejecutar el DELETE, y una vez que ejecuto la declaración, siempre verifico que el recuento de filas es lo que espero antes de comprometerme.
Rachel
55
@Rachel Es bueno que tengas algo que funcione para ti. ¿Puedes hacer que todos hagan eso?
Andy
36

Principalmente es para evitar que las claves foráneas se conviertan en un tremendo dolor. Digamos que tiene dos tablas: Customer y CustomerAddress. La clave principal para ambos es una columna llamada id, que es una columna de identidad (int).

Ahora necesita que se haga referencia al ID de cliente desde CustomerAddress. No puede nombrar el id de la columna, obviamente, por lo que debe ir con customer_id.

Esto lleva a un par de problemas. Primero, debe recordar constantemente cuándo llamar a la columna "id" y cuándo llamarla "customer_id". Y si arruinas esto, lleva al segundo problema. Si tienes una consulta grande con una docena de combinaciones, y no devuelve ningún dato, diviértete jugando Where's Waldo y buscando este error tipográfico:

ON c.id = ca.id

Vaya, debería haber sido ON c.id = ca.customer_id. O mejor aún, nombre sus columnas de identidad descriptivamente, para que así sea ON c.customer_id = ca.customer_id. Luego, si accidentalmente usa el alias de tabla incorrecto en alguna parte, customer_id no será una columna en esa tabla, y obtendrá un buen error de compilación, en lugar de resultados vacíos y entrecerrado de código posterior.

Por supuesto, hay casos en los que esto no ayuda, como si necesita múltiples relaciones de clave externa de una tabla a otra tabla única, pero nombrar todas las claves principales "id" tampoco ayuda.

db2
fuente
27

Aquí hay un resumen de todas las respuestas sobre las ventajas obtenidas de la convención de no usar un nombre común para todas las claves principales:

  • Menos errores, ya que los campos de identidad no tienen el mismo nombre

    No puede escribir por error una consulta que se une en B.Id = B.Idlugar de A.Id = B.Id, porque los campos de identidad nunca se nombrarán exactamente igual.

  • Nombres de columna más claros.

    Si observa una columna llamada CustomerId, inmediatamente sabe qué datos hay en esa columna. Si el nombre de la columna era algo genérico Id, entonces también necesita conocer el nombre de la tabla para saber qué datos contiene la columna.

  • Evita los alias de columna innecesarios

    Ahora puede escribir SELECT CustomerId, ProductIddesde una consulta que se une Customerscon Products, en lugar deSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Permite la JOIN..USINGsintaxis

    Puede unir tablas con la sintaxis Customer JOIN Products USING (CustomerId), en lugar deCustomer JOIN Products ON Customer.Id = Products.Id

  • La clave es más fácil de encontrar en las búsquedas.

    Si está buscando el campo de identidad de un cliente en una solución grande, buscar CustomerIdes mucho más útil que buscarId

Si puede pensar en otras ventajas que tiene esta convención de nombres, avíseme y la agregaré a la lista.

Si decide utilizar nombres de columna únicos o idénticos para los campos de identidad depende de usted, pero independientemente de lo que elija, sea coherente :)

Rachel
fuente
12

Para copiar mi respuesta de la pregunta vinculada:

Hay una situación en la que pegar "ID" en cada tabla no es la mejor idea: la USINGpalabra clave, si es compatible. Lo usamos a menudo en MySQL.

Por ejemplo, si tiene fooTableuna columna fooTableIdy barTableuna clave foránea fooTableId, entonces sus consultas pueden construirse como tal:

SELECT fooTableId, fooField1, barField2 FROM fooTable INNER JOIN barTable USING (fooTableId)

No solo guarda la escritura, sino que es mucho más legible en comparación con la alternativa:

SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)
Izkata
fuente
9

Después de normalizar un esquema de base de datos para limitar la redundancia, las tablas se dividen en tablas más pequeñas con relaciones establecidas (una a una, una a muchas, muchas a muchas). En el proceso, pueden aparecer campos individuales en la tabla original en varias tablas normalizadas.

Por ejemplo, una base de datos para un blog podría verse así en su forma no normalizada, suponiendo una restricción única en Author_Nickname.

| Author_Nickname | Author_Email | Post_Title | Post_Body |
+-----------------+--------------+------------+-----------+
| dave            | dave@x.com   | Blah       | Bla bla   |
| dave            | dave@x.com   | Stuff      | I like    |
| sophie          | s@oph.ie     | Lorem      | Ipsum     |

Normalizarlo produciría dos tablas:

Autor:

| Author_Nickname | Author_Email |
+-----------------+--------------+
| dave            | dave@x.com   |
| sophie          | s@oph.ie     |

Enviar

| Author_Nickname | Post_Title | Post_Body |
+-----------------+------------+-----------+
| dave            | Blah       | Bla bla   |
| dave            | Stuff      | I like    |
| sophie          | Lorem      | Ipsum     |

Aquí Author_Nickname sería una clave principal para la tabla de autor y una clave externa en la tabla de publicación. Incluso si Author_Nickname aparece en dos tablas, todavía corresponde a una sola unidad de información, es decir. cada nombre de columna corresponde a un solo campo .

En muchos casos, no puede haber una restricción única en los campos originales, por lo que se utiliza un campo artificial numérico como clave principal. Esto no cambia el hecho de que cada nombre de columna todavía representa un solo campo. En el diseño tradicional de la base de datos, los nombres de columnas individuales corresponden a campos individuales, incluso si no son claves. (por ejemplo, uno usaría part.partname y client.clientname en lugar de part.name y client.name ). Esta es la razón de la existencia de INNER JOIN ... USING <key>y las NATURAL JOINsintaxis.

Sin embargo, hoy en día, y con las capas ORM fácilmente disponibles en muchos idiomas, las bases de datos a menudo se diseñan como una capa de persistencia para los lenguajes OO, en los que es natural que las variables que tienen el mismo papel en diferentes clases se llamen de la misma manera ( part.name y client.name , no part.partname y client.clientname ). En ese contexto, tiendo a usar 'ID' para mis claves principales.

Stilgar
fuente
7

Un proveedor externo que contratamos para crear algo para nosotros en realidad nombró a todas sus columnas de identidad Ident solo para evitar usar Id.

Usar "Ident" en lugar de "Id" realmente no resuelve nada si "Ident" termina siendo utilizado en todas sus tablas.

Hay un buen artículo sobre convenciones de codificación SQL en el sitio de Drupal que indica una buena práctica para esta situación:

Es una buena práctica prefijar los nombres de las tablas con el nombre del módulo para evitar posibles conflictos de espacio de nombres.

Desde este punto de vista, CustomerProductId y AgencyGroupAssignmentId tienen sentido de uso. Sí, es bastante detallado. Podrías acortarlo, pero el punto más importante por el que debes preocuparte es si el desarrollador que te sigue entenderá lo que querías decir . Los ID precedidos por nombres de tabla detallados no deberían dejar ambigüedad en cuanto a lo que son. Y (para mí) eso es más importante que guardar unas pocas teclas.

Aaron
fuente
7

Nombre las columnas CustomerID en lugar de ID, así que cada vez que escribo

FROM dbo.Customers AS c JOIN dbo.CustomerOrders AS o

Mensaje de SQL sugiere inmediatamente lo siguiente

ON c.CustomerID = o.CustomerID 

Me ahorra algunas pulsaciones de teclas. Sin embargo, creo que las convenciones de denominación son muy subjetivas y, como tal, no tengo una opinión sólida de una forma u otra.

Alaska
fuente
5

Es la misma razón por la que no nombraría todos sus campos varchar como "UserText" y "UserText1", o por qué no usaría "UserDate" y "UserDate1".

Por lo general, si tiene un campo de identidad en una tabla, es su clave principal. ¿Cómo construiría una tabla secundaria con una clave externa para una tabla primaria si la clave primaria en ambas tablas fuera id?

No todos están de acuerdo con esta metodología, pero en mis bases de datos asigno una abreviatura única a cada tabla. El PK para esa tabla se llamaría PK_ [abbrv] ID. SI se usa como FK en cualquier lugar, entonces usaría FK_ [abbrv] ID. Ahora tengo cero conjeturas para descubrir cuáles son las relaciones de la tabla.

DForck42
fuente
5

Básicamente por la misma razón por la que normalmente no se nombran los parámetros parámetro1, parámetro2 ... es preciso, pero no descriptivo. Si ve TableId, entonces probablemente pueda asumir con seguridad que se usa para contener un paquete para Table, independientemente del contexto.

En cuanto a quien usó Ident, él pierde completamente el punto, dado que puede elegir entre Ident y Id. Ident es aún más confuso que Id.

Fuera de contexto, se puede suponer que Id es la clave principal de alguna tabla (no es extremadamente útil a menos que el id sea un guid), pero Ident ni siquiera te dice eso (o al menos a mí). Eventualmente descubriría que Ident es la abreviatura de identidad (de una forma u otra), pero el tiempo que pasé descubriendo eso se desperdiciaría.

jmoreno
fuente
3

Use un prefijo para poder usar el mismo nombre en contextos de clave primaria y clave externa, de modo que pueda realizar natural join/ join ... using.

DrPizza
fuente