Why use %d in php when in function

$wpdb->prepare() supports a small subset of the sprintf() arguments. The %d is a placeholder for an integer (not a decimal, that would be %f).

Use %d when you want to send a real integer to the database, use %s for strings.

An example:

$post_id  = '2';
$prepared = $wpdb->prepare(
    "SELECT * FROM $wpdb->posts WHERE post_id = %d", 
    $post_id 
);

Here we use %d to make sure we query for an integer. If we would use %s, there would be no strict match, because $post_id is a string in our PHP snippet.

$wpdb->prepare() is useful in cases when you are not sure in what format the value is.

So how do you know the required type for each field? You can look up this information in wp-admin/includes/schema.php. Example for the posts table:

CREATE TABLE $wpdb->posts (
  ID bigint(20) unsigned NOT NULL auto_increment,
  post_author bigint(20) unsigned NOT NULL default '0',
  post_date datetime NOT NULL default '0000-00-00 00:00:00',
  post_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
  post_content longtext NOT NULL,
  post_title text NOT NULL,
  post_excerpt text NOT NULL,
  post_status varchar(20) NOT NULL default 'publish',
  comment_status varchar(20) NOT NULL default 'open',
  ping_status varchar(20) NOT NULL default 'open',
  post_password varchar(20) NOT NULL default '',
  post_name varchar(200) NOT NULL default '',
  to_ping text NOT NULL,
  pinged text NOT NULL,
  post_modified datetime NOT NULL default '0000-00-00 00:00:00',
  post_modified_gmt datetime NOT NULL default '0000-00-00 00:00:00',
  post_content_filtered longtext NOT NULL,
  post_parent bigint(20) unsigned NOT NULL default '0',
  guid varchar(255) NOT NULL default '',
  menu_order int(11) NOT NULL default '0',
  post_type varchar(20) NOT NULL default 'post',
  post_mime_type varchar(100) NOT NULL default '',
  comment_count bigint(20) NOT NULL default '0',
  PRIMARY KEY  (ID),
  KEY post_name (post_name),
  KEY type_status_date (post_type,post_status,post_date,ID),
  KEY post_parent (post_parent),
  KEY post_author (post_author)
) $charset_collate;\n";

Everything declared as bigint or int requires %d, because these fields are integers. *text, varchar and datetime require %s.

You can also query for that information programmatically in your PHP scripts:

global $wpdb;

$table_data = $wpdb->get_results( "DESCRIBE $wpdb->posts" );
print '<pre>' . print_r( $table_data, 1 ) . '</pre>';

The result looks like this:

Array
(
    [0] => stdClass Object
        (
            [Field] => ID
            [Type] => bigint(20) unsigned
            [Null] => NO
            [Key] => PRI
            [Default] => 
            [Extra] => auto_increment
        )

    [1] => stdClass Object
        (
            [Field] => post_author
            [Type] => bigint(20) unsigned
            [Null] => NO
            [Key] => MUL
            [Default] => 0
            [Extra] => 
        )

    [2] => stdClass Object
        (
            [Field] => post_date
            [Type] => datetime
            [Null] => NO
            [Key] => 
            [Default] => 0000-00-00 00:00:00
            [Extra] => 
        )

    [3] => stdClass Object
        (
            [Field] => post_date_gmt
            [Type] => datetime
            [Null] => NO
            [Key] => 
            [Default] => 0000-00-00 00:00:00
            [Extra] => 
        )

    [4] => stdClass Object
        (
            [Field] => post_content
            [Type] => longtext
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [5] => stdClass Object
        (
            [Field] => post_title
            [Type] => text
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [6] => stdClass Object
        (
            [Field] => post_excerpt
            [Type] => text
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [7] => stdClass Object
        (
            [Field] => post_status
            [Type] => varchar(20)
            [Null] => NO
            [Key] => 
            [Default] => publish
            [Extra] => 
        )

    [8] => stdClass Object
        (
            [Field] => comment_status
            [Type] => varchar(20)
            [Null] => NO
            [Key] => 
            [Default] => open
            [Extra] => 
        )

    [9] => stdClass Object
        (
            [Field] => ping_status
            [Type] => varchar(20)
            [Null] => NO
            [Key] => 
            [Default] => open
            [Extra] => 
        )

    [10] => stdClass Object
        (
            [Field] => post_password
            [Type] => varchar(20)
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [11] => stdClass Object
        (
            [Field] => post_name
            [Type] => varchar(200)
            [Null] => NO
            [Key] => MUL
            [Default] => 
            [Extra] => 
        )

    [12] => stdClass Object
        (
            [Field] => to_ping
            [Type] => text
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [13] => stdClass Object
        (
            [Field] => pinged
            [Type] => text
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [14] => stdClass Object
        (
            [Field] => post_modified
            [Type] => datetime
            [Null] => NO
            [Key] => 
            [Default] => 0000-00-00 00:00:00
            [Extra] => 
        )

    [15] => stdClass Object
        (
            [Field] => post_modified_gmt
            [Type] => datetime
            [Null] => NO
            [Key] => 
            [Default] => 0000-00-00 00:00:00
            [Extra] => 
        )

    [16] => stdClass Object
        (
            [Field] => post_content_filtered
            [Type] => longtext
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [17] => stdClass Object
        (
            [Field] => post_parent
            [Type] => bigint(20) unsigned
            [Null] => NO
            [Key] => MUL
            [Default] => 0
            [Extra] => 
        )

    [18] => stdClass Object
        (
            [Field] => guid
            [Type] => varchar(255)
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [19] => stdClass Object
        (
            [Field] => menu_order
            [Type] => int(11)
            [Null] => NO
            [Key] => 
            [Default] => 0
            [Extra] => 
        )

    [20] => stdClass Object
        (
            [Field] => post_type
            [Type] => varchar(20)
            [Null] => NO
            [Key] => MUL
            [Default] => post
            [Extra] => 
        )

    [21] => stdClass Object
        (
            [Field] => post_mime_type
            [Type] => varchar(100)
            [Null] => NO
            [Key] => 
            [Default] => 
            [Extra] => 
        )

    [22] => stdClass Object
        (
            [Field] => comment_count
            [Type] => bigint(20)
            [Null] => NO
            [Key] => 
            [Default] => 0
            [Extra] => 
        )
)

You could use now the Type entry to determine the correct placeholder. I wouldn’t do that for the core tables, it is easier just use the values you found in schema.php. Custom tables from third party code is another story, it might be sometimes useful to inspect those tables.